洛谷 3391 【模板】文艺平衡树 Treap区间翻转
【题解】
用Treap维护这个序列。
加入的时候直接插入到末尾,这样Treap就变成一棵以插入时间先后为排序关键字的二叉搜索树。
对于翻转操作,我们分裂出需要翻转的区间,给这个区间的root打一个翻转标记。
在分裂、合并、输出的时候,遇到翻转标记,就把左右儿子交换,同时下传标记。
1 #include<cstdio> 2 #include<algorithm> 3 #define ls (a[u].l) 4 #define rs (a[u].r) 5 using namespace std; 6 const int maxn=200010; 7 int n,m,x,y,z,l,r,tot,root; 8 struct treap{int l,r,v,rnd,size,rot;}a[maxn]; 9 inline int read(){ 10 int k=0,f=1; char c=getchar(); 11 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 12 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 13 return k*f; 14 } 15 void newnode(int val){a[++tot]=(treap){0,0,val,rand(),1,0};} 16 void update(int u){a[u].size=a[ls].size+a[rs].size+1;} 17 void rotate(int u){if(a[u].rot) a[u].rot^=1,swap(ls,rs),a[ls].rot^=1,a[rs].rot^=1;} 18 void split(int u,int k,int &x,int &y){ 19 rotate(u); 20 if(!k){x=0; y=u; return;} 21 if(a[u].size==k){x=u; y=0; return;} 22 if(a[ls].size>=k) split(ls,k,x,ls),y=u; 23 else split(rs,k-a[ls].size-1,rs,y),x=u; 24 update(u); 25 } 26 int merge(int x,int y){ 27 if(!x||!y) return x+y; 28 rotate(x); rotate(y); 29 if(a[x].rnd<a[y].rnd){ 30 a[x].r=merge(a[x].r,y); update(x); return x; 31 } 32 else{ 33 a[y].l=merge(x,a[y].l); update(y); return y; 34 } 35 } 36 void put(int u){ 37 rotate(u); 38 if(ls) put(ls); 39 printf("%d ",a[u].v); 40 if(rs) put(rs); 41 } 42 int main(){ 43 n=read(); m=read(); 44 for(int i=1;i<=n;i++) newnode(i),root=merge(root,tot); 45 while(m--){ 46 l=read()-1; r=read(); 47 split(root,l,x,y); split(y,r-l,y,z); 48 a[y].rot^=1; 49 root=merge(merge(x,y),z); 50 } 51 put(root); 52 return 0; 53 }