csu1365 Play with Chain
很显然的splay,第一次用splay操作区间...我实在佩服这个targan大佬,居然搞出这么牛逼的平衡树,调了大概5个小时终于搞定了。。
#include<cstdio> #include<cstdlib> #include<iostream> #include<string> #include<set> #include<algorithm> #include<vector> #include<queue> #include<list> #include<cmath> #include<cstring> #include<map> #include<stack> using namespace std; #define INF 0x3f3f3f3f #define maxn 300005 #define ull unsigned long long #define ll long long #define hashmod 99999839 #define mod 9997 struct tree{//splay树 int sz[2];//以当前结点为根的左右子树大小,不包括当前结点 int son[2];//当前结点的左右儿子 int fa;//当前结点的父亲 int reverse;//翻转标记 int v;//当前结点表示的权值 }a[maxn]; int root;//根节点 int len; int n,m,x,y,z; bool f; int isrson(int p,int f){ return a[f].son[1] == p; } void update(int p){//更新p结点的size if(a[p].son[0] != -1) a[p].sz[0] = a[a[p].son[0]].sz[0] + a[a[p].son[0]].sz[1] + 1; else a[p].sz[0] = 0; if(a[p].son[1] != -1) a[p].sz[1] = a[a[p].son[1]].sz[0] + a[a[p].son[1]].sz[1] + 1; else a[p].sz[1] = 0; } void pushdown(int p){ swap(a[p].son[0],a[p].son[1]); update(p); a[p].reverse ^= 1; int ls = a[p].son[0],rs = a[p].son[1]; if(ls != -1) a[ls].reverse ^= 1; if(rs != -1) a[rs].reverse ^= 1; } int find(int x){//找到序列第x个数对应的结点 int p = root; for(;;){ if(a[p].reverse) pushdown(p); if(a[p].sz[0] >= x) p = a[p].son[0]; else if(a[p].sz[0] + 1 == x) return p; else x = x - a[p].sz[0] - 1,p = a[p].son[1]; } } void changeson(int p,int f,int v){//把p作为f的v儿子,p,f不一定存在 if(f != -1) a[f].son[v] = p; if(p != -1) a[p].fa = f; if(f == -1) root = p; } void rotate(int p){ int f = a[p].fa,g = a[f].fa; int u = isrson(p,f),v = isrson(f,g); changeson(a[p].son[u^1],f,u),changeson(f,p,u^1),changeson(p,g,v);//改变p,f,g的父子关系 update(f),update(p); } void splay(int p,int tar){ if(a[p].fa == tar) return; while(a[a[p].fa].fa != tar && a[p].fa != tar){ int f = a[p].fa,g = a[f].fa; int u = isrson(p,f),v = isrson(f,g); if(u ^ v) rotate(p),rotate(p); else rotate(f),rotate(p); } if(a[p].fa != tar) rotate(p); } void getsection(int x,int y){//得到[x,y]区间 splay(find(x - 1),-1),splay(find(y + 1),root); } void build(int l,int r){ len++; int p = len; int mid = (l + r) >> 1; a[p].v = mid,a[p].sz[0] = a[p].sz[1] = 0; a[p].son[0] = a[p].son[1] = -1; if(l == r) return; if(l <= mid - 1) changeson(len + 1,p,0),build(l,mid-1); if(mid + 1 <= r) changeson(len + 1,p,1),build(mid+1,r); update(p); } void flip(int x,int y){ getsection(x,y);//得到区间[x,y]后打标记 int p = a[a[root].son[1]].son[0]; a[p].reverse ^= 1; } void cut(int x,int y,int z){//cut [x,y] z 把区间x,y剪切到z位置后 //先得到区间[x,y],将其x-1rotate到根,将y+1rotate到根的儿子,则y+1结点的左儿子为根的树即为该区间 getsection(x,y); int p = a[a[root].son[1]].son[0]; a[a[p].fa].son[0] = -1; update(a[p].fa),update(root); int t = p; p = find(z); splay(p,-1),p = find(z + 1),splay(p,root); p = a[root].son[1],a[p].son[0] = t,a[t].fa = p; update(p),update(root); } void print(int p){ if(p == -1) return; if(a[p].reverse) pushdown(p),update(p); print(a[p].son[0]); if(a[p].v != 0 && a[p].v != n + 1) if(!f) printf("%d",a[p].v),f = true; else printf(" %d",a[p].v); print(a[p].son[1]); } int main(){ freopen("a.in","r",stdin); freopen("b.out","w",stdout); char op[10]; while(~scanf("%d%d",&n,&m)){ if(n < 0 && m < 0) break; len = 0,root = 1,f = false; build(0,n+1); a[root].fa = -1; for(int i = 1;i <= m;++i){ scanf("%s",op); if(op[0] == 'C'){ scanf("%d%d%d",&x,&y,&z); ++x,++y,++z; cut(x,y,z); continue; } scanf("%d%d",&x,&y); ++x,++y; flip(x,y); } print(root),putchar('\n'); } return 0; }