找平衡树练习题的时候发现了这道神题,可以说这道题是近几年单考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 ",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 }