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;
}

  

 

posted @ 2020-10-15 21:02  我微笑不代表我快乐  阅读(148)  评论(0编辑  收藏  举报