BZOJ2329 HNOI2011 括号修复 splay+贪心

找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考splay的巅峰之作了。

 

题目大意:给出括号序列,实现区间翻转,区间反转和区间更改。查询区间最少要用几次才能改成合法序列。

 

分析:

  首先我们单看查询操作。不妨想象一下存在着一个栈,往里面入栈和出栈,那么从原序列中取出一对(),对应着一个入和一个出。那么当)的前面再也找不到(与之对应的时候,)就要被更改成(。

  这有什么用呢?我们会发现,删除一对()对答案不具有影响。接着我们删除所有可以匹配的括号,得到一个))))))((((((这样的序列。

  这个的答案是什么?由于对答案没有影响,我们单独考虑这个序列。我们把这个序列分成两部分考虑,对于由)构成的部分,取2的最大倍数个,其中的一半都要换成(,对于可能的多余的一个,我们一定将它变成(,接着用同样的想法考虑另一半,由于另一半一定是2的倍数个,所以答案加上另一半的一半。总的来说,答案等于ceil(“)序列长度”/2)+ceil("(序列长度"/2)

  修改操作怎么实现?假设我们有两棵括号序列正好相反的平衡树,那么区间反转操作可以视为将另一棵的这一部分嫁接过来,再把自己的这一部分嫁接过去。接着update答案即可。在草稿纸上面画一下区间翻转操作,发现翻转后的原序列与它的反序列在图形上对称。即翻转后序列的)序列等于反转后(序列长度。反之也是如此。那么这两个操作就很好解决了。

  接下来是区间更改操作,它可以覆盖掉另外两个操作,同时反转操作对它产生反转更改标记的影响。

 

代码:

splay容易打错,我用了treap替代它。

  1 #include<bits/stdc++.h>
  2 #pragma GCC optimize(2)
  3 #define L (t[now].ch[0])
  4 #define R (t[now].ch[1])
  5 using namespace std;
  6 
  7 struct node{
  8     int data,sz,lk[2],rk[2];
  9     int ch[2],key;
 10     int lzfz,lzrp,lzinv;
 11 }t[320000];
 12 int n,m,Num;
 13 int root1;
 14 char str[120000];
 15 
 16 void push_down1(int now){
 17     if(now == 0) return;
 18     swap(t[now].lk[0],t[now].rk[1]);
 19     swap(t[now].rk[0],t[now].lk[1]);
 20     swap(L,R);
 21     t[L].lzfz ^= 1; t[R].lzfz ^= 1;t[now].lzfz ^= 1;
 22 }
 23 
 24 void push_down2(int now){
 25     if(now == 0) return;
 26     swap(t[now].lk[0],t[now].lk[1]);
 27     swap(t[now].rk[0],t[now].rk[1]);
 28     t[L].data *= -1;t[R].data *= -1;
 29     t[L].lzinv ^= 1; t[R].lzinv ^= 1;t[now].lzinv ^= 1;
 30     t[L].lzrp *= -1; t[R].lzrp *= -1;
 31 }
 32 
 33 void push_down3(int now){
 34     if(now == 0) return;
 35     t[L].lzfz = t[L].lzinv = 0; t[R].lzfz = t[R].lzinv = 0;
 36     t[L].data = t[R].data = t[now].lzrp;
 37     t[L].lzrp = t[now].lzrp;t[R].lzrp = t[now].lzrp;
 38     //last buding paichu
 39     t[L].lk[0] = t[L].lk[1] = t[L].rk[0] = t[L].rk[1] = 0;
 40     t[R].lk[0] = t[R].lk[1] = t[R].rk[0] = t[R].rk[1] = 0;
 41     //last buding paichu
 42     if(t[now].lzrp == 1){
 43     t[L].rk[0] = t[L].lk[1] = t[L].sz;
 44     t[R].rk[0] = t[R].lk[1] = t[R].sz;
 45     }else{
 46     t[L].lk[0] = t[L].rk[1] = t[L].sz;
 47     t[R].lk[0] = t[R].rk[1] = t[R].sz;
 48     }
 49     t[now].lzrp = 0;
 50 }
 51 
 52 void push_up(int now){
 53     if(t[now].lzfz) push_down1(now);
 54     if(t[now].lzinv) push_down2(now);
 55     if(t[now].lzrp) push_down3(now);
 56     //rouyan chachu loudong
 57     if(t[L].lzfz) push_down1(L);if(t[R].lzfz) push_down1(R);
 58     if(t[L].lzinv) push_down2(L);if(t[R].lzinv) push_down2(R);
 59     if(t[L].lzrp) push_down3(L);if(t[R].lzrp) push_down3(R);
 60 
 61     t[now].sz = t[L].sz + t[R].sz + 1;
 62     t[now].lk[0] = t[L].lk[0];t[now].rk[0] = t[L].rk[0];
 63     t[now].lk[1] = t[L].lk[1];t[now].rk[1] = t[L].rk[1];
 64     if(t[now].data == 1)t[now].rk[0]++;
 65     else if(t[now].rk[0])t[now].rk[0]--;else t[now].lk[0]++;
 66     if(t[now].data == -1)t[now].rk[1]++;
 67     else if(t[now].rk[1])t[now].rk[1]--;else t[now].lk[1]++;
 68     if(t[now].rk[0] >= t[R].lk[0])t[now].rk[0] += t[R].rk[0]-t[R].lk[0];
 69     else t[now].lk[0] += t[R].lk[0]-t[now].rk[0],t[now].rk[0]=t[R].rk[0];
 70     if(t[now].rk[1] >= t[R].lk[1]) t[now].rk[1] += t[R].rk[1]-t[R].lk[1];
 71     else t[now].lk[1] += t[R].lk[1]-t[now].rk[1],t[now].rk[1]=t[R].rk[1];
 72 }
 73 
 74 int merge(int r1,int r2){
 75     if(t[r1].lzfz) push_down1(r1); if(t[r1].lzinv) push_down2(r1);
 76     if(t[r1].lzrp) push_down3(r1); if(t[r2].lzfz) push_down1(r2);
 77     if(t[r2].lzinv) push_down2(r2); if(t[r2].lzrp) push_down3(r2);
 78     if(r1 == 0) return r2; if(r2 == 0) return r1;
 79     if(t[r1].key < t[r2].key){
 80     t[r1].ch[1] = merge(t[r1].ch[1],r2);
 81     push_up(r1); return r1;
 82     }else{
 83     t[r2].ch[0] = merge(r1,t[r2].ch[0]);
 84     push_up(r2); return r2;
 85     }
 86 }
 87 
 88 pair <int,int> split(int now,int sz){
 89     if(t[now].lzfz) push_down1(now);
 90     if(t[now].lzinv) push_down2(now);
 91     if(t[now].lzrp) push_down3(now);
 92     if(sz == 0) return make_pair(0,now);
 93     if(sz >= t[now].sz) return make_pair(now,0);
 94     pair <int,int> pi;
 95     if(t[L].sz >= sz)
 96     pi=split(L,sz),t[now].ch[0]=pi.second,pi.second=now;
 97     else
 98     pi=split(R,sz-t[L].sz-1),t[now].ch[1]=pi.first,pi.first=now;
 99     push_up(pi.first); push_up(pi.second);
100     return pi;
101 }
102 
103 void flip(int l,int r){
104     pair <int,int> pi = split(root1,r);
105     pair <int,int> pp = split(pi.first,l-1);
106     int now = pp.second;
107     if(t[now].lzfz) push_down1(now);
108     if(t[now].lzinv) push_down2(now);
109     if(t[now].lzrp) push_down3(now);
110     t[now].lzfz ^= 1;
111     root1 = merge(merge(pp.first,pp.second),pi.second);
112 }
113 
114 void link(int l,int r){
115     pair <int,int> pi = split(root1,r);
116     pair <int,int> pp = split(pi.first,l-1);
117     int now = pp.second;
118     if(t[now].lzfz) push_down1(now);
119     if(t[now].lzinv) push_down2(now);
120     if(t[now].lzrp) push_down3(now);
121     t[now].lzinv ^= 1;t[now].data *= -1;
122     root1 = merge(merge(pp.first,pp.second),pi.second);
123 }
124 
125 void get_ans(int l,int r){
126     pair <int,int> pi = split(root1,r);
127     pair <int,int> pp = split(pi.first,l-1);
128     int now = pp.second;
129     if(t[now].lzfz) push_down1(now);
130     if(t[now].lzrp) push_down2(now);
131     if(t[now].lzinv) push_down3(now);
132     int ans = ceil(t[now].lk[0]/2.0)+ceil(t[now].rk[0]/2.0);
133     printf("%d\n",ans);
134     root1 = merge(merge(pp.first,pp.second),pi.second);
135 }
136 
137 void insert(int &now,char what,int place){
138     t[++Num].data=(what=='('?1:-1);t[Num].sz=1;t[Num].key=rand()%6547845;
139     if(what == '(')t[Num].rk[0] = 1,t[Num].lk[1] = 1;
140     else t[Num].lk[0] = 1,t[Num].rk[1] = 1;
141     pair<int,int> p1 = split(now,place);
142     now = merge(merge(p1.first,Num),p1.second);
143 }
144 
145 void read(){
146     scanf("%d%d",&n,&m);
147     for(int i=1;i<=n;i++){
148     char ch = getchar();
149     while(ch != '(' && ch != ')') ch = getchar();
150     str[i] = ch;
151     }
152     for(int i=1;i<=n;i++){
153     if(str[i] == '('){insert(root1,'(',i);}
154     else {insert(root1,')',i);}
155     }
156 }
157 
158 void work(){
159     for(int i=1;i<=m;i++){
160     int cg,l,r; scanf("%d%d%d",&cg,&l,&r);
161     switch(cg){
162     case 0:{get_ans(l,r);break;}
163     case 2:{flip(l,r);break;}
164     case 1:{link(l,r);break;}
165     }
166     }
167 }
168 
169 int main(){
170     srand(123456451);
171     read();
172     work();
173     return 0;
174 }

 

posted @ 2018-01-05 13:32  社会主义市场经济  阅读(199)  评论(0编辑  收藏  举报