有关splay的区间操作

splay可以进行区间操作。
我们以BZOJ3223文艺平衡树为例题:

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

Input

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n

Output

输出一行n个数字,表示原始序列经过m次变换后的结果

Sample Input

5 3

1 3

1 3

1 4

Sample Output

4 3 2 1 5


这道题要我们做的就是进行区间翻转。如果我们要进行区间翻转,那我们首先得找到区间。找到区间的方法很简单,比如我们要找区间[l,r],则我们先找到l的前驱,把它splay到根,然后再找到r的后继,把它splay到根的右儿子。则r的后继的左子树就是我们要找的区间。
这个做法十分容易证明,将l的前驱splay到根,则根的右子树就是区间[l,n],然后将r的后继splay到根的右儿子,则根的右儿子的左儿子就是区间[l,r]。然后我们对于区间[l,r]就可以进行操作。
而对于区间翻转,我们只要swap每个点的左儿子和右儿子即可。但是我们不用直接操作到底,我们也可以打一个懒惰标记。直到要查询下面的时候再下推标记即可。
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
int read(){
    char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int n,m,root;
struct Splay{
    int fa[MAXN],son[MAXN][2],siz[MAXN],add[MAXN];
    void up(int k){
        siz[k]=siz[son[k][0]]+siz[son[k][1]]+1;
    }
    void down(int k){
        if(add[k]){
            swap(son[k][0],son[k][1]);
            add[son[k][0]]^=1;add[son[k][1]]^=1;
            add[k]=0;
        }
    }
    void rotate(int x,int &k){
        int f=fa[x],gran=fa[f],opt;
        opt=(son[f][1]==x);
        if(f==k) k=x;else son[gran][son[gran][1]==f]=x;
        son[f][opt]=son[x][opt^1];fa[son[f][opt]]=f;
        son[x][opt^1]=f;fa[f]=x;fa[x]=gran;
        siz[x]=siz[f];up(f);
    }
    void splay(int x,int &k){
        while(x!=k){
            int f=fa[x],gran=fa[f];
            if(f!=k) rotate((son[f][0]==x)^(son[gran][0]==f)?x:f,k);
            rotate(x,k);
        }
    }
    void build(int l,int r,int f){
        if(l>r) return;
        int mid=(l+r)>>1;if(mid<f) son[f][0]=mid;else son[f][1]=mid;
        fa[mid]=f;siz[mid]=1;
        if(l==r) return;
        build(l,mid-1,mid);build(mid+1,r,mid);
        up(mid);
    }
    int find(int x,int k){
        down(x);int s=siz[son[x][0]];
        if(s+1==k) return x;
        if(k<=s) return find(son[x][0],k);
        else return find(son[x][1],k-s-1);
    }
    void revers(int l,int r){
        int x=find(root,l),y=find(root,r+2);
        splay(x,root);splay(y,son[root][1]);
        int pl=son[y][0];add[pl]^=1;
    }
}T;
int main()
{
    n=read();m=read();
    root=(n+3)>>1;T.build(1,n+2,root);
    for(int i=1;i<=m;i++){
        int l=read(),r=read();
        T.revers(l,r);
    }
    for(int i=2;i<=n+1;i++) printf("%d ",T.find(root,i)-1);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/stevensonson/article/details/80302393