hdu 1890 Robotic Sort(splay 区间反转+删点)

时间:2023-03-08 19:06:14

题目链接:hdu 1890 Robotic Sort

题意:

给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次。

题解:

典型的splay区间翻转+删点。

我们把数据排序,然后记录一下每个数原来的位置,然后splay建树的时候用原来的位置来对应,这样val[i].second就直接是这个数在splay中的那个节点。

(当然你也可以普通建树,然后手动记录位置)。

然后我们把要找的那个数对应的节点旋转到根,然后根左边的size+i就是当前数的答案,然后翻转一下前面的数,再删除根。

 #include<bits/stdc++.h>
#define F(i,a,b) for(int i=a;i<=b;++i)
using namespace std; const int N=1e5+;
int n,a[N],size[N],ch[N][],f[N],tot,root;bool rev[N];
pair<int,int>val[N]; void rev1(int x){if(!x)return;swap(ch[x][],ch[x][]);rev[x]^=;} void pb(int x){
if(rev[x]){
rev1(ch[x][]);
rev1(ch[x][]);
rev[x]=;
}
} void up(int x){
size[x]=;
if(ch[x][])size[x]+=size[ch[x][]];
if(ch[x][])size[x]+=size[ch[x][]];
} void rotate(int x){
int y=f[x],w=ch[y][]==x;
ch[y][w]=ch[x][w^];
if(ch[x][w^])f[ch[x][w^]]=y;
if(f[y]){
int z=f[y];
if(ch[z][]==y)ch[z][]=x;
if(ch[z][]==y)ch[z][]=x;
}
f[x]=f[y];ch[x][w^]=y;f[y]=x;up(y);
} void splay(int x,int w){
int s=,i=x,y;a[]=x;
while(f[i])a[++s]=i=f[i];
while(s)pb(a[s--]);
while(f[x]!=w){
y=f[x];
if(f[y]!=w){if((ch[f[y]][]==y)^(ch[y][]==x))rotate(x);else rotate(y);}
rotate(x);
}
if(!w)root=x;
up(x);
} void newnode(int &r,int fa,int k)
{
r=k,f[r]=fa,rev[r]=,ch[r][]=ch[r][]=;
} void build(int &x,int l,int r,int fa){
int mid=(l+r)>>;
newnode(x,fa,mid);
if(l<mid)build(ch[x][],l,mid-,x);
if(r>mid)build(ch[x][],mid+,r,x);
up(x);
return;
} int getmax(int x)
{
pb(x);
while(ch[x][])x=ch[x][],pb(x);
return x;
} void delroot()
{
if(ch[root][])
{
int m=getmax(ch[root][]);
splay(m,root);
ch[m][]=ch[root][];
f[ch[root][]]=m;
root=m,f[m]=,up(m);
}else root=ch[root][],f[root]=;
} int main(){
while(scanf("%d",&n),n)
{
F(i,,n)scanf("%d",&val[i].first),val[i].second=i;
sort(val+,val++n),build(root,,n,);
F(i,,n-)
{
splay(val[i].second,);
rev1(ch[root][]);
printf("%d ",i+size[ch[root][]]);
delroot();
}
printf("%d\n",n);
}
return ;
}