题目链接:
题意:一个数列两种操作:(1)将一个区间翻转;(2)将一个区间剪下放到另一个位置。
思路:翻转区间[A,B],将A-1,B+1分别调整到根和根节点的右子树;则[A,B]被调整到根节点右子树的左子树,记录翻转标记;剪切时第一步跟翻转一样,第二部将根节点右子树的左子树P剪下,设新插入的位置为C,将C和C+1分别调整到根和根节点的右子树,此时根节点的右子树的左子树为空,将P插在该位置。
int n,m;int c[N][2],p[N],s[N],sign[N];int root;void update(int f,int x,int flag){ p[x]=f; if(!f) return; c[f][flag]=x; s[f]=1+s[c[f][0]]+s[c[f][1]];}void down(int x){ if(!sign[x]) return; sign[x]=0; swap(c[x][0],c[x][1]); sign[c[x][0]]^=1; sign[c[x][1]]^=1;}void rotate(int x){ int P=p[x],G=p[P]; if(c[P][0]==x) { update(P,c[x][1],0); update(x,P,1); update(G,x,!(c[G][0]==P)); } else { update(P,c[x][0],1); update(x,P,0); update(G,x,!(c[G][0]==P)); }}void splay(int x,int &goal){ int P=p[x],G=p[P],limit=p[goal]; while(P!=limit) { if(G!=limit&&(c[G][0]==P)==(c[P][0]==x)) rotate(P); rotate(x); P=p[x]; G=p[P]; } goal=x; down(goal);}int select(int x){ int t=root; while(1) { down(t); if(s[c[t][0]]+1==x) break; if(s[c[t][0]]+1>x) t=c[t][0]; else x-=s[c[t][0]]+1,t=c[t][1]; } return t;}int build(int L,int R){ if(L>R) return 0; int m=(L+R)>>1; update(m,build(L,m-1),0); update(m,build(m+1,R),1); return m;}int main(){ while(scanf("%d%d",&n,&m),n>=0&&m>=0) { memset(sign,0,sizeof(sign)); memset(s,0,sizeof(s)); memset(p,0,sizeof(p)); memset(c,0,sizeof(c)); root=build(1,n+2); int A,B,C,i,r1,r2; char op[10]; while(m--) { scanf("%s",op); if(op[0]=='C') { scanf("%d%d%d",&A,&B,&C); r1=select(A); r2=select(B+2); splay(r1,root); splay(r2,c[root][1]); i=c[c[root][1]][0]; c[c[root][1]][0]=0; update(c[root][1],0,0); update(root,c[root][1],1); r1=select(C+1); r2=select(C+2); splay(r1,root); splay(r2,c[root][1]); c[c[root][1]][0]=i; update(c[root][1],i,0); update(root,c[root][1],1); } else { scanf("%d%d",&A,&B); r1=select(A); r2=select(B+2); splay(r1,root); splay(r2,c[r1][1]); i=c[root][1]; i=c[i][0]; sign[i]^=1; } } for(i=2;i