人生第一个splay题。
区间分裂,区间合并还有区间翻转都是比较裸的板子
一个区间分裂成三个区间还是写一个两两分裂的函数比较好写(
区间合并也是
感觉其他也没有什么要针对这个题说的
如果用动态内存的话建议用数组指针,不然会MLE(窝也不造是不是叫这个)
只要splay写好了就能过
以及代码如下
#include<bits\stdc++.h> using namespace std; #define l ch[0] #define r ch[1] struct node{ int val,siz; int flp; node *ch[2]; void maintain(){ siz=1; if(ch[0]) siz+=ch[0]->siz; if(ch[1]) siz+=ch[1]->siz; } }; const int maxn = 312345; node nodes[maxn]; int tot; int size(node *o){ if(o==NULL){ return 0; } return o->siz; } void zg(node* &o,int d){ node *k=o->ch[d]; o->ch[d]=k->ch[1^d]; k->ch[1^d]=o; o=k; o->ch[1^d]->maintain(); o->maintain(); } node *newnode(int x){ node * ret = &nodes[tot++]; ret->flp=0; ret->val = x; ret->siz = 0; ret->l=ret->r=NULL; return ret; } void push(node *rot){ rot->flp=0; swap(rot->l,rot->r); if(rot->l) rot->l->flp ^=1; if(rot->r) rot->r->flp ^=1; } int splay(node* &rot,int x){ if(rot->flp) push(rot); if(size(rot->l)+1==x) return 2; int d = size(rot->l)+1 > x? 0:1; if(d) x-=size(rot->l)+1; int k = splay(rot->ch[d],x); if(k==2) return d; if(k==d){ zg(rot,d);zg(rot,d); } else{ zg(rot->ch[d],k);zg(rot,d); } return 2; } void fnd(node* &root,int x){ if(!root) return; int k = splay(root,x); if(k!=2) zg(root,k); } void out(node *rot,int d,int k){ if(rot->r) out(rot->r,d+1,-1); for(int i = 0;i<d;i++) printf(" "); if(k==0){ printf("--"); } else{ printf(" "); if(k==-1) printf("/"); else printf("\\"); } printf("%d(%d)\n",rot->val,rot->siz); if(rot->l) out(rot->l,d+1,1); } void print(node *rot){ puts("-------------"); if(!rot) puts("NULL!"); else out(rot,0,0); puts("============="); } node *splite(node *&rot,int x){ if(x==0){ node *ret = rot; rot=NULL; return ret; } fnd(rot,x); node *ret = rot->r; rot->r=NULL; rot->maintain(); return ret; } node *merg(node* L,node* R){ if(L){ fnd(L,L->siz); L->r=R; L->maintain(); return L; } if(R){ fnd(R,1); R->l=L; R->maintain(); return R; } return NULL; } void cut(int L,int R,int C,node* &root){ node *right=splite(root,R); node *left=splite(root,L-1); swap(left,root); left=merg(left,right); right=splite(left,C); left=merg(left,root); root=merg(left,right); } void flip(int L,int R,node* &root){ node *right=splite(root,R); node *left=splite(root,L-1); swap(left,root); root->flp ^=1 ; if(left) root=merg(left,root); if(right){ fnd(right,1); right->l=root; right->maintain(); root=right; } } node *build(int n){ node *root = newnode(1); root->maintain(); for(int i =2;i<=n;i++){ node *k = newnode(i); k->l = root; root = k; root->maintain(); } return root; } int ans[maxn]; int len; void mid(node *root){ if(root->flp) push(root); if(root->l) mid(root->l); ans[len++]=root->val; if(root->r) mid(root->r); } int main(){ int n,m; char arr[10]; while(~scanf("%d %d",&n,&m) && (n+1)||(m+1)){ tot=0; node *root = build(n); int L,R,C; while(m--){ scanf("%s %d %d",arr,&L,&R); if(arr[0]=='C'){ scanf("%d",&C); cut(L,R,C,root); // print(root); } else{ flip(L,R,root); // print(root); } } len=0; mid(root); for(int i = 0;i<n;i++) printf(i<n-1?"%d ":"%d\n",ans[i]); } return 0; }
===================================update====================
又写了一发,在右边添加了一个虚拟节点,优化了cut和flip的代码量
node *getseg(int L,int R,node* &root){ //goal is return->l and father is return L--,R++; if(L){ fnd(root,L); fnd(root->r,R-L); return root->r; } else{ fnd(root,R); return root; } } void flip(node* &root,int L,int R){ node * k = getseg(L,R,root); k->l->flp ^= 1; } void cut(node* &root,int L,int R,int c){ node * fa = getseg(L,R,root); node * k = fa->l; fa->l=NULL; fa->maintain(); root->maintain(); if(c){ fnd(root,c); fnd(root,c+1); root->l->r=k; root->l->maintain(); root->maintain(); } else{ fnd(root,1); root->l=k; root->maintain(); } }