P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列

(10 mins to read)

给定一个括号序列,要求支持下面的操作

  • 替换某个区间的所有括号为左括号或者右括号
  • 将一个区间的括号进行翻转
  • 将一个区间的括号进行反转,左括号<->右括号
  • 询问一个区间内至少改变几个括号才能成为一个合法的括号序列

毒瘤题不过我连询问的答案是什么都想错了(好菜啊)先消掉合法的括号,最后肯定是))))((((的形式,维护区间前缀最小和后缀最大即可,由于有反转操作还要维护区间前缀最大和后缀最小。感觉自己对平衡树维护的题还是不熟,每次都一堆错误。最主要的问题就是忘记了本节点信息,主要是线段树的信息完全由子节点合并而来,但是在平衡树中本节点的信息是不包含在子节点中的。此外在建树的时候每个节点的信息都要记录下来,而不是像线段树一样只在叶子节点的时候记录,然后其余节点直接通过pushup得到即可,切记!!然后就是下传标记的问题,主要是反转和覆盖操作的先后顺序会有影响,然后我竟然就不会了(不是和加法乘法一样吗, 好久没写了 )在覆盖的时候,可以把反转和翻转的标记清零。在反转的时候,需要把覆盖的标记取反。然后下传的时候先传反转,然后再传覆盖,因为这个时候肯定是先有反转再有覆盖的,否则覆盖会把反转的标记清掉。顺便回忆一下加法和乘法标记,在乘法的时候要把加法标记也乘一下,在下传的时候先传乘法再传加法。这种多标记的问题,最好对每个标记写一个函数,否则会很乱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, q;
char c[N];
int rt;
int ch[N][2], sz[N], val[N], fa[N], lmn[N], rmn[N], lmx[N], rmx[N], sum[N];
int rev[N], cov[N], inv[N];
bool rs(int x) { return ch[fa[x]][1]==x; }
void up(int p)
{
if(!p) return;
int l = ch[p][0], r = ch[p][1];
sz[p] = sz[l] + sz[r] + 1;
lmn[p] = min(lmn[l], sum[l]+val[p]+lmn[r]);
lmx[p] = max(lmx[l], sum[l]+val[p]+lmx[r]);
rmn[p] = min(rmn[r], sum[r]+val[p]+rmn[l]);
rmx[p] = max(rmx[r], sum[r]+val[p]+rmx[l]);
sum[p] = sum[l] + sum[r] + val[p];
}
void setv(int p, int v)
{
if(!p) return;
val[p] = v, sum[p] = v*sz[p];
lmn[p] = rmn[p] = min(0, sum[p]);
lmx[p] = rmx[p] = max(0, sum[p]);
cov[p] = v;
inv[p] = 0;
rev[p] = 0;
}
void setrev(int p)
{
if(!p) return;
swap(ch[p][0], ch[p][1]);
swap(lmn[p], rmn[p]);
swap(lmx[p], rmx[p]);
rev[p] ^= 1;
}
void setinv(int p)
{
if(!p) return;
swap(lmn[p], lmx[p]);
swap(rmn[p], rmx[p]);
lmn[p] *= -1;
lmx[p] *= -1;
rmn[p] *= -1;
rmx[p] *= -1;
sum[p] *= -1;
val[p] *= -1;
inv[p] ^= 1;
cov[p] *= -1;
}
void down(int p)
{
if(inv[p])
{
inv[p] = 0;
setinv(ch[p][0]); setinv(ch[p][1]);
}
if(cov[p])
{
setv(ch[p][0], cov[p]); setv(ch[p][1], cov[p]);
cov[p] = 0;
}
if(rev[p])
{
rev[p] = 0;
setrev(ch[p][0]); setrev(ch[p][1]);
}
}
void build(int l, int r, int f)
{
if(l>r) return;
int p = (l+r)>>1, v = (c[p-1]=='(' ? 1 : -1);
sz[p] = 1, sum[p] = val[p] = v;
fa[p] = f, ch[f][p>f] = p;
if(l==r)
{
lmx[p] = rmx[p] = max(0, v);
lmn[p] = rmn[p] = min(0, v);
return;
}
build(l, p-1, p); build(p+1, r, p);
up(p);
}
void rotate(int x)
{
int y = fa[x], z = fa[y], k = rs(x), w = ch[x][k^1];
ch[y][k] = w; fa[w] = y;
ch[z][rs(y)] = x; fa[x] = z;
ch[x][k^1] = y; fa[y] = x;
up(y); up(x);
}
void splay(int x, int g=0)
{
while(fa[x]!=g)
{
int y = fa[x];
if(fa[y]!=g) (rs(x)==rs(y) ? rotate(y) : rotate(x));
rotate(x);
}
if(!g) rt = x;
}
int kth(int p, int k)
{
down(p);
if(ch[p][0]&&sz[ch[p][0]]>=k) return kth(ch[p][0], k);
else if(sz[ch[p][0]]+1==k) return p;
else return kth(ch[p][1], k-sz[ch[p][0]]-1);
}
int split(int l, int r)
{
int x = kth(rt, l-1), y = kth(rt, r+1);
splay(x); splay(y, x);
return ch[y][0];
}
void replace(int l, int r, int v)
{
int x = split(l, r), y = fa[x];
setv(x, v);
up(y); up(fa[y]);
}
void reverse(int l, int r)
{
int x = split(l, r), y = fa[x];
setrev(x);
up(y); up(fa[y]);
}
void invert(int l, int r)
{
int x = split(l, r), y = fa[x];
setinv(x);
up(y); up(fa[y]);
}
int main()
{
scanf("%d%d", &n, &q);
scanf("%s", c+1);
build(1, n+2, 0);
rt = (n+3)>>1;
for(int i=1; i<=q; i++)
{
static char com[10], cc[2];
static int l, r;
scanf("%s%d%d", com, &l, &r);
++l, ++r;
if(com[0]=='R')
{
scanf("%s", cc);
replace(l, r, (cc[0]=='(' ? 1 : -1));
}
else if(com[0]=='Q')
{
int x = split(l, r);
int pmn = lmn[x], smx = rmx[x];
int y = fa[x];
up(y); up(fa[y]);
assert(pmn<=0); assert(smx>=0);
printf("%d\n", ((-pmn+1)>>1)+((smx+1)>>1));
}
else if(com[0]=='S') reverse(l, r);
else if(com[0]=='I') invert(l, r);
}
return 0;
}