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

Posted hooying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
    }
}

以上是关于P3165 [CQOI2014]排序机械臂 (splay)的主要内容,如果未能解决你的问题,请参考以下文章

P3165 [CQOI2014]排序机械臂

洛谷P3165 [CQOI2014]排序机械臂

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

洛谷P3165 [CQOI2014]排序机械臂splay

[CQOI2014]排序机械臂

bzoj 3506[Cqoi2014]排序机械臂 - splay