题意:
有T(T<10)组测试数据,然后有一个数字N(N<100000),接下来的一行里有N个字符,每个字符是’(‘或’)’,现在有三种操作
(1)”set l r c”,表示将区间[l,r]里的所有元素改变为c,c是’(‘或’)’的其中一种。
(2)”reverse l r”,表示将区间[l,r]里的’(‘与’)’对调。
(3)”query l r”,表示查询区间[l,r]是否为一个合法的括号序列。
解析:
如果我们可以令’(‘为-1,而’)’为1,注意到如果在区间[l,r]里从l出发不断向后扫直到r,同时求和,在这个过程中,如果和的最大值是小于等于0的,并且最后的和是等于0的,那么这个序列是合法的,即输出”YES”。
那么这就要求在线段树的结点中要保存一个sumv域和maxv域(即最大值),对于操作”set”和操作”reverse”分别有两个延迟操作与之对应,即cover和XOR。因为操作”reverse”,要求对换1和-1,则为了维护max域,所以在线段树的结点中多增加一个域,min(表示最小值),这样在进行操作”reverse”时,就可以通过取反操作,得到这个区间的max。
当要向下传递延迟操作的时候,要先传递”set”操作的标记,即cover,后传递XOR。因为对一个区间进行”set”操作的时候,会将之前的”reverse”操作的标记置0(因为之前的”reverse”操作是失效的),如果一个区间同时有cover和XOR,那么一个是”set”操作先到达这个区间,然后”reverse”操作再到达这个区间。
区间合并的时候,维护当前区间的min域,维护的是从左儿子的min域 和 左儿子的sum加上右儿子的min中取最小值。max域的更新也类似。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 1000005;
char str[N];
int n;
int cover[N<<2], XOR[N<<2];
int maxv[N<<2], minv[N<<2], sumv[N<<2];
void setValue(int o, int L, int R, int val) {
cover[o] = val;
int len = (R - L + 1), tmp = len * val;
sumv[o] = tmp;
maxv[o] = max(tmp, 0);
minv[o] = min(tmp, 0);
XOR[o] = 0;
}
void reversal(int o) {
if(cover[o]) {
cover[o] *= -1;
sumv[o] *= -1;
XOR[o] = 0;
} else {
XOR[o] ^= 1;
sumv[o] *= -1;
}
int a = -maxv[o], b = -minv[o];
maxv[o] = max(a, b);
minv[o] = min(a, b);
}
void pushDown(int o, int L, int R) {
int M = (L + R)/2;
if(cover[o]) {
setValue(lson, cover[o]);
setValue(rson, cover[o]);
cover[o] = 0;
}
if(XOR[o]) {
reversal(ls);
reversal(rs);
XOR[o] = 0;
}
}
void pushUp(int o) {
sumv[o] = sumv[ls] + sumv[rs];
minv[o] = min(minv[ls], sumv[ls] + minv[rs]);
maxv[o] = max(maxv[ls], sumv[ls] + maxv[rs]);
}
void build(int o, int L, int R) {
XOR[o] = cover[o] = 0;
if(L == R) {
int val;
val = (str[L] == '(') ? -1 : 1;
setValue(o, L, R, val);
return ;
}
int M = (L + R)/2;
build(lson);
build(rson);
pushUp(o);
}
void modify(int o, int L, int R, int ql, int qr, int val) {
if(ql <= L && R <= qr) {
if(val == 2) reversal(o);
else setValue(o, L, R, val);
return ;
}
pushDown(o, L, R);
int M = (L + R)/2;
if(ql <= M) modify(lson, ql, qr, val);
if(qr > M) modify(rson, ql, qr, val);
pushUp(o);
}
void query(int o, int L, int R, int ql, int qr, int& _sum, int& _max) {
if(ql <= L && R <= qr) {
_max = maxv[o], _sum = sumv[o];
return ;
}
pushDown(o, L, R);
int M = (L + R)/2;
int suml = 0, sumr = 0, maxl = 0, maxr = 0;
if(ql <= M) query(lson, ql, qr, suml, maxl);
if(qr > M) query(rson, ql, qr, sumr, maxr);
_sum = suml + sumr;
_max = max(maxl, suml + maxr);
}
void solve() {
int q, ql, qr, val;
char cmd[10], ch[10];
scanf("%d", &q);
while(q--) {
scanf("%s", cmd);
if(cmd[0] == 's') {
scanf("%d%d%s", &ql, &qr, ch);
val = (ch[0] == '(') ? -1 : 1;
modify(1, 0, n-1, ql, qr, val);
}else if(cmd[0] == 'r') {
scanf("%d%d", &ql, &qr);
modify(1, 0, n-1, ql, qr, 2);
}else {
scanf("%d%d", &ql, &qr);
int _sum = 0, _max = 0;
query(1, 0, n-1, ql, qr, _sum, _max);
printf("%s\n", (_max <= 0 && _sum == 0) ? "YES" : "NO");
}
}
}
int main() {
int T, cas = 1;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
scanf("%s", str);
build(1, 0, n-1);
printf("Case %d:\n", cas++);
solve();
puts("");
}
return 0;
}