codevs3303 翻转区间

题意: 给一个数列1...n,经过m次区间翻转,问最终数列。n,m≤100000

splay维护,翻转时把区间旋转为一棵子树,对子树的根标记翻转,查询遇到标记时下传标记。

#include<cstdio>
#define N 100010
int chs[N][2];
bool rv[N];
int v[N];
int sz[N];
int p,root,X;
int t=0,n,m;
void rev(int);
inline int&ch(int a,int b){
    rev(a);
    return chs[a][b];
}
inline void upd(int w){
    sz[w]=sz[ch(w,0)]+sz[ch(w,1)]+1;
}
void rot(int&w,int c){
    int u=ch(w,c);
    ch(w,c)=ch(u,c^1);
    upd(ch(u,c^1)=w);
    upd(w=u);
}
bool nth(int&w,int s){
    if(s==X)return 0;
    int c=X>s,cc;
    int&u=ch(w,c);
    cc=nth(u,c?s+sz[ch(u,0)]+1:s-sz[ch(u,1)]-1);
    if(t){
        if(c==cc)rot(w,c);
        else rot(ch(w,c),cc);
        rot(w,c);
    }
    t^=1;
    upd(w);
    return c;
}
void getnth(int&rt,int x){
    t=0;
    X=x;
    int c=nth(rt,sz[ch(rt,0)]+1);
    if(t)rot(rt,c);
}
void rev(int w){
    if(!rv[w]||!w)return;
    int c=chs[w][0];
    rv[w]=0;
    rv[chs[w][0]=chs[w][1]]^=1;
    rv[chs[w][1]=c]^=1;
}
void print(int x){
    if(!x)return;
    print(ch(x,0));
    if(x>=2&&x<=n+1)printf("%d ",v[x]);
    print(ch(x,1));
}
int main(){
    int l,r;
    scanf("%d%d",&n,&m);
    for(int i=2;i<=n+1;i++)v[i]=i-1;
    root=n+2;
    for(int i=n+2;i>0;i--)ch(i,0)=i-1;
    for(int i=1;i<=n+2;i++)sz[i]=i;
    while(m--){
        scanf("%d%d",&l,&r);
        getnth(root,r+2);
        getnth(ch(root,0),l);
        rv[ch(ch(root,0),1)]^=1;
    }
    print(root);
    return 0;
}

第一次yy出splay怎么写。。

你可能感兴趣的:(codevs3303 翻转区间)