大意略。
思路:更新、查询比较好实现,关键是如何去判断左右括号是合法的序列呢?我参考了网上的思路,即把'('看做-1,')'看做1,只要询问区间总和为0,且区间连续最大和的值小于等于0,则说明该序列合法。
区间连续最大和的状态更新:
sumv[o] = sumv[lc]+sumv[rc];
maxv[o] = max(maxv[lc], sumv[lc]+maxv[rc]);
minv[o] = min(minv[lc], sumv[lc]+minv[rc]);
#include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <vector> using namespace std; const int maxn = 100010; #define lc o*2 #define rc o*2+1 int n, m; char str[maxn+10]; int cover[maxn<<2], XOR[maxn<<2]; int sumv[maxn<<2], maxv[maxn<<2], minv[maxn<<2]; void FXOR(int o) //异或操作 { if(cover[o] != 0) cover[o] = -cover[o]; else XOR[o] ^= 1; } void pushup(int o) //区间从左往右连续最大值,要么是左边连续最大和,要么是左边总和与右边连续最大和相加。 { sumv[o] = sumv[lc] + sumv[rc]; maxv[o] = max(maxv[lc], sumv[lc] + maxv[rc]); minv[o] = min(minv[lc], sumv[lc] + minv[rc]); } void pushdown(int o, int m) { int temp; if(cover[o] != 0) //存在覆盖标记 { cover[lc] = cover[rc] = cover[o]; sumv[lc] = cover[o] * (m-(m>>1)); sumv[rc] = cover[o] * (m>>1); maxv[lc] = max(-1, sumv[lc]); maxv[rc] = max(-1, sumv[rc]); minv[lc] = min(1, sumv[lc]); minv[rc] = min(1, sumv[rc]); XOR[lc] = XOR[rc] = 0; cover[o] = 0; } if(XOR[o]) //如果存在异或标记,总和取反,最大值变为最小值的相反数,最小值类似。 { FXOR(lc), FXOR(rc); sumv[lc] = -sumv[lc]; sumv[rc] = -sumv[rc]; temp = maxv[lc]; maxv[lc] = -minv[lc]; minv[lc] = -temp; temp = maxv[rc]; maxv[rc] = -minv[rc]; minv[rc] = -temp; XOR[o] = 0; } } void build(int o, int L, int R) { cover[o] = XOR[o] = 0; if(L == R) { if(str[L] == '(') { sumv[o] = maxv[o] = minv[o] = -1; } else { sumv[o] = maxv[o] = minv[o] = 1; } return ; } int M = L + (R-L)/2; build(lc, L, M); build(rc, M+1, R); pushup(o); } void update(int o, int y1, int y2, int L, int R, char op) { if(y1 <= L && y2 >= R) { if(op == '(') { cover[o] = -1; maxv[o] = -1, minv[o] = -(R-L+1); sumv[o] = -(R-L+1); XOR[o] = 0; } else if(op == ')') { cover[o] = 1; maxv[o] = R-L+1, minv[o] = 1; sumv[o] = R-L+1; XOR[o] = 0; } else if(op == 'r') //取反 { FXOR(o); sumv[o] = -sumv[o]; int temp = maxv[o]; maxv[o] = -minv[o]; minv[o] = -temp; } return ; } pushdown(o, R-L+1); int M = L + (R-L)/2; if(y1 <= M) update(lc, y1, y2, L, M, op); if(y2 > M) update(rc, y1, y2, M+1, R, op); pushup(o); } int query1(int o, int y1, int y2, int L, int R) { if(y1 <= L && y2 >= R) return sumv[o]; int ans = 0, M = L + (R-L)/2; pushdown(o, R-L+1); if(y1 <= M) ans += query1(lc, y1, y2, L, M); if(y2 > M) ans += query1(rc, y1, y2, M+1, R); //pushup(o); return ans; } int query2(int o, int y1, int y2, int L, int R) //定义变量为a, b, c,就错了,我嘞个去。 { if(y1 <= L && y2 >= R) return maxv[o]; int ans = 0, M = L + (R-L)/2; pushdown(o, R-L+1); //int a = query2(lc, y1, y2, L, M), b = query1(lc, y1, y2, L, M), c = query2(rc, y1, y2, M+1, R); if(y2 <= M) ans = query2(lc, y1, y2, L, M); //区间全在左边 else if(y1 > M) ans = query2(rc, y1, y2, M+1, R); //区间全在右边 else ans = max(query2(lc, y1, y2, L, M), query1(lc, y1, y2, L, M)+query2(rc, y1, y2, M+1, R)); //中间 //pushup(o); return ans; } void read_case() { scanf("%d%s%d", &n, str, &m); build(1, 0, n-1); } void solve() { read_case(); char op[20]; int y1, y2; while(m--) { scanf("%s", op); if(op[0] == 's') { scanf("%d%d%s", &y1, &y2, op); update(1, y1, y2, 0, n-1, op[0]); } else if(op[0] == 'r') { scanf("%d%d", &y1, &y2); update(1, y1, y2, 0, n-1, op[0]); } else { scanf("%d%d", &y1, &y2); if((y2-y1) & 1) { int o1, t2; o1 = query1(1, y1, y2, 0, n-1), t2 = query2(1, y1, y2, 0, n-1); if(o1 == 0 && t2 <= 0) printf("YES\n"); else printf("NO\n"); } else printf("NO\n"); } } printf("\n"); } int main() { int T, times = 0; scanf("%d", &T); while(T--) { printf("Case %d:\n", ++times); solve(); } return 0; }