Splay区间翻转操作
[Cerc2007]robotic sort
在一个车间里有N(1<=N<=100000)个零件排成一列,已知他们各自的高度,现在要将他们按高度排列成升序序列
规定只能使用如下方法:
找到最低的零件的位置P1,将区间[1,P1]反转,再找到第二低的零件的位置P2,将区间[2,P2]反转……
要求你的程序输出P1,P2,P3…
如果有一样高的零件,那么优先处理在原始序列中靠前的零件。
对于样例
3 4 5 1 6 2
第一次,先找到“1”的位置,它在第四个位置,它将与第一个位置这一段的数字反转
得到1 5 4 3 6 2,对应的输出为4
第二次,先找到"2"的位置,它在第六个位置,它将与第二个位置这一段的数字反转
得到1 2 6 3 4 5,对应的输出为6
第三次,先找到"3"的位置,它在第四个位置,它将与第三个位置这一段的数字反转
得到1 2 3 6 4 5,对应的输出为4
样例输入
6
3 4 5 1 6 2
样例输出
4 6 4 5 6 6
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,a[100010],key[100010],b[100010],p[100010],root,sz;
int fa[100010],ch[100010][3],size[100010],rev[100010],pos[100010];
int cmp(int x,int y)
{
return a[x]<a[y]||a[x]==a[y]&&x<y;
}
int get(int x)
{
return ch[fa[x]][1]==x;
}
void update(int x)
{
int l=ch[x][0],r=ch[x][1];
size[x]=1;
if(l)
size[x]+=size[l];
if(r)
size[x]+=size[r];
}
void pushdown(int x)
{
int l=ch[x][0],r=ch[x][1];
if(!rev[x])
return ;
rev[l]^=1;
rev[r]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
void rotate(int x)
{
pushdown(fa[x]);
pushdown(x);
int f=fa[x];
int ff=fa[f];
int sum=get(x);
//建立x与其祖父点ff之间的关系
if(ff)
ch[ff][ch[ff][1]==f]=x;
fa[x]=ff;
//重新建立x与父亲点f的关系
//f变成x的子结点
fa[f]=x;
//将x的左(右)结点变成f的右(左)结点
ch[f][sum]=ch[x][sum^1];
fa[ch[f][sum]]=f;
ch[x][sum^1]=f;
//想清楚上面语句的逻辑关系
update(f);
update(x);
}
void splay(int x,int tar)
{
for(int f;(f=fa[x])!=tar;rotate(x))
if(fa[f]!=tar)
rotate(get(x)==get(f)?f:x);
if(!tar)
root=x;
}
int find(int x)
{
int rt=root;
while(true)
{
pushdown(rt);
if(x<=size[ch[rt][0]])
rt=ch[rt][0];
else
{
int num=size[ch[rt][0]]+1;
if(num==x)
return rt;
x-=num;
rt=ch[rt][1];
}
}
}
int build(int l,int r)
{
if(l==r)
{
sz++;
pos[b[l]]=sz;
size[sz]=1;
return sz;
}
if(l>r)
return 0;
int now=++sz;
int mid=(l+r)/2;
pos[b[mid]]=now;
ch[now][0]=build(l,mid-1);
ch[now][1]=build(mid+1,r);
fa[ch[now][0]]=now;
fa[ch[now][1]]=now;
size[now]=size[ch[now][0]]+size[ch[now][1]]+1;
return now;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p[i]=i;
}
sort(p+1,p+n+1,cmp);
int cnt=0;
b[1]=0; //新加一个头结点,值最小
b[n+2]=n+2; //新加一个尾结点,值最大
for(int i=1;i<=n;i++)
b[p[i]+1]=i;
root=build(1,n+2);
for(int i=1;i<=n;i++)
{
splay(pos[i],0);
int ans=size[ch[root][0]];
printf("%d",ans);
if(i!=n)
printf(" ");
else
printf("\n");
splay(find(i),0);
splay(find(ans+2),find(i));
rev[ch[ch[root][1]][0]]^=1;
}
return 0;
}

浙公网安备 33010602011771号