• 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("
    ");
            splay(find(i),0);
            splay(find(ans+2),find(i));
            rev[ch[ch[root][1]][0]]^=1;
        }   
        return 0;
    }
    

      

  • 相关阅读:
    Docker
    Docker
    Docker
    Docker
    Docker
    Docker
    pandas——向已经存在的excel数据写入data
    python——利用UI选择路径
    python——装饰器的使用
    python——生成器(协程)gevent多任务
  • 原文地址:https://www.cnblogs.com/cutemush/p/13823148.html
Copyright © 2020-2023  润新知