UOJ Logo zgjkt的博客

博客

【bzoj3223】Tyvj 1729 文艺平衡树

2015-04-30 22:05:01 By zgjkt

题目大意

您需要写一种数据结构,来维护一个有$n$个数的有序数列,其中需要提供以下$m$次操作:翻转区间

例如原有序序列是$“5 4 3 2 1”$,翻转区间是$[2,4]$的话,结果是$“5 2 3 4 1”$

数据范围

$n,m\leqslant 100000$


题解

splay区间翻转

注意弄多两个边界节点,防止出现各种各样的小问题,具体怎么做看代码吧!


程序

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define inf 0x3f3f3f3f
#define maxn 105000
using namespace std;

int t[maxn][2],f[maxn],size[maxn],rev[maxn];
int n,m,rt;
inline void pushup(int x){size[x]=size[t[x][0]]+size[t[x][1]]+1;}
inline void pushdown(int x){if (rev[x]){swap(t[x][0],t[x][1]);rev[x]^=1;rev[t[x][1]]^=1;rev[t[x][0]]^=1;}}
inline void rotate(int x,int &k){
    int y=f[x],z=f[y],l,r;
    if (t[y][0]==x) l=0;else l=1;r=l^1;
    if (y==k) k=x;
    else {if (t[z][0]==y) t[z][0]=x;else t[z][1]=x;}
    f[x]=z;f[y]=x;f[t[x][r]]=y;
    t[y][l]=t[x][r];t[x][r]=y;
    pushup(y);pushup(x);
}
inline void splay(int x,int &k){
    while(x!=k){
        int y=f[x],z=f[y];
        if (y!=k){
            if ((t[y][0]==x)^(t[z][0]==y)) rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
}

void build(int l,int r,int last){
    if (l>r) return;
    if (l==r){
        f[l]=last;size[l]=1;
        if (l<last) t[last][0]=l;
        else t[last][1]=l;
    }
    int mid=(l+r)>>1;
    build(l,mid-1,mid);build(mid+1,r,mid);
    f[mid]=last;pushup(mid);
    if (mid<last) t[last][0]=mid;
    else t[last][1]=mid;
}
int findsum(int x,int rank){
    pushdown(x);
    if(size[t[x][0]]+1==rank) return x;
    else if(size[t[x][0]]>=rank)return findsum(t[x][0],rank);
    else return findsum(t[x][1],rank-size[t[x][0]]-1);
}    
inline void rever(int l,int r){
    int x=findsum(rt,l),y=findsum(rt,r+2);
    splay(x,rt);splay(y,t[x][1]);
    rev[t[y][0]]^=1;
}
int main(){
    scanf("%d%d",&n,&m);
    build(1,n+2,0);rt=(n+3)>>1;
    For(i,1,m){
        int a,b;
        scanf("%d%d",&a,&b);
        rever(a,b);
    }
    For(i,2,n+1) printf("%d ",findsum(rt,i)-1);
    puts("");
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。