P3165 [CQOI2014]排序机械臂 (splay)

题意

\(n\)个物品,依次排列,每个物品都有一个高度\(hi\)
\(n\)次操作,第\(i\)次操作将区间 [位置\(i\),第\(i\)低的物品(多个时取靠左的优先)的位置]翻转
回答一个序列,第\(i\)个数表示每次操作前第\(i\)低的物品所在位置

思路

利用\(splay\)进行多次区间翻转的一道题。
建立\(n\)个节点,节点\(i\)表示位置\(i\),一开始我们将splay类似线段树一样建好,其结点中序遍历就是\(1,2,...,n−1,n\)
我们将原本的物品高度升序排列,高度相同按位置升序排列。
然后每次就是找到第\(i\)高度的物品的结点\(k\),此时\(splay\)的结点\(k\)\(splay\)中序遍历所在的位置(从左到右数第几个),就是经过\(i−1\)次翻这个位置所对应的是最初始序列的第\(k\)个位置。
将结点\(k\)移动到根,然后查询左儿子子树大小就是答案了。
翻转原序列就是\(splay\)的一个基本操作了。
注意:每次要先把元素旋转到根得到他的排名在反转区间,所以在这里\(splay\)里面也要加\(push\)下推。

#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
const int inf = 0x3f3f3f3f;
struct node
{
    int p,id;
    bool operator < (const node &t)const
    {
        if(p==t.p)return id<t.id;
        return p<t.p;
    }
}a[maxx];
int ch[maxx][2],fa[maxx],siz[maxx],lazy[maxx];
int rt;
int get(int x)
{
    return ch[fa[x]][1]==x;
}
void update(int x)
{
    if(x)siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void pushdown(int x)
{
    if(x&&lazy[x])
    {
        lazy[ch[x][0]]^=1;
        lazy[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
        lazy[x]=0;
    }
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],k=get(x);
    pushdown(x);pushdown(y);
    ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
    ch[x][k^1]=y;fa[y]=x;fa[x]=z;
    if(z)ch[z][ch[z][1]==y]=x;
    update(y);update(x);
}
void splay(int x,int goal)
{
    for(int y;(y=fa[x])!=goal;rotate(x))
    {
        pushdown(fa[y]),pushdown(y),pushdown(x);
        if(fa[y]!=goal)rotate((get(x)==get(y))?y:x);
    }
    if(goal==0)rt=x;
}
int findkth(int k)
{
    int x=rt;
    while(1)
    {
        pushdown(x);
        if(k<=siz[ch[x][0]])x=ch[x][0];
        else
        {
            k-=siz[ch[x][0]]+1;
            if(!k)return x;
            x=ch[x][1];
        }
    }
}
int build(int l,int r,int f)
{
    if(l>r)return 0;
    int mid=(l+r)/2;
    fa[mid]=f;
    ch[mid][0]=build(l,mid-1,mid);
    ch[mid][1]=build(mid+1,r,mid);
    update(mid);
    return mid;
}
void reverse(int x,int y)
{
    int l=x-1,r=y+1;
    l=findkth(l);r=findkth(r);
    splay(l,0);splay(r,l);
    lazy[ch[ch[rt][1]][0]]^=1;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n+1;i++)
        scanf("%d",&a[i].p),a[i].id=i;
    a[1].id=1,a[1].p=-inf;
    a[n+2].id=n+2,a[n+2].p=inf;
    sort(a+1,a+1+n+2);
    rt=build(1,n+2,0);
    for(int i=2;i<=n+1;i++)
    {
        splay(a[i].id,0);
        int ans=siz[ch[rt][0]]+1;
        printf("%d ",ans-1);
        reverse(i,ans);
    }
}
posted @ 2020-03-14 19:01  灰灰烟影  阅读(164)  评论(0编辑  收藏  举报