洛谷 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 }
View Code

 

posted @ 2017-12-22 19:43  Driver_Lao  阅读(848)  评论(0编辑  收藏  举报