UESTC_1546
这个题目可以借用判断合法括号序列的办法,将’(’看作1,将’)’看作-1,之后从左向右扫描一个序列并将扫描到的值累加起来,在这个过程中如果任意时刻这些值的和都不小于0,并且最后的时候这些值的和为0,那么就说明这个括号序列是合法的。
于是我们只要再用线段树实现修改及查询的操作,这个题目就算是解决了。为了便于修改和查询,我们可以用两个标记to、rev,to表示这个区间是否被set,rev表示这个区间是否被翻转。同时我们可以维护3个值lmin、lmax、sum,lmin表示从当前区间左端点开始最小的前缀和,lmax表示从当前区间开始最大的前缀和,sum表示当前区间的和。
#include<stdio.h> #include<string.h> #define MAXD 100010 int N, M, to[4 * MAXD], rev[4 * MAXD], lmin[4 * MAXD], lmax[4 * MAXD], sum[4 * MAXD]; char b[MAXD]; void Swap(int &x, int &y) { int t; t = x, x = -y, y = -t; } void pushdown(int cur, int x, int y) { int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1; if(to[cur] != -1) { to[ls] = to[rs] = to[cur]; rev[ls] = rev[rs] = 0; if(to[cur]) { sum[ls] = mid - x + 1, sum[rs] = y - mid; lmin[ls] = lmin[rs] = 0; lmax[ls] = mid - x + 1, lmax[rs] = y - mid; } else { sum[ls] = -(mid - x + 1), sum[rs] = -(y - mid); lmin[ls] = -(mid - x + 1), lmin[rs] = -(y - mid); lmax[ls] = lmax[rs] = 0; } to[cur] = -1; } if(rev[cur]) { rev[ls] ^= 1, rev[rs] ^= 1; sum[ls] = -sum[ls], sum[rs] = -sum[rs]; Swap(lmin[ls], lmax[ls]), Swap(lmin[rs], lmax[rs]); rev[cur] = 0; } } void update(int cur) { int ls = cur << 1, rs = cur << 1 | 1; sum[cur] = sum[ls] + sum[rs]; lmin[cur] = lmin[ls]; if(sum[ls] + lmin[rs] < lmin[cur]) lmin[cur] = sum[ls] + lmin[rs]; lmax[cur] = lmax[ls]; if(sum[ls] + lmax[rs] > lmax[cur]) lmax[cur] = sum[ls] + lmax[rs]; } void build(int cur, int x, int y) { int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1; to[cur] = -1, rev[cur] = 0; if(x == y) { if(b[x] == '(') sum[cur] = lmax[cur] = 1, lmin[cur] = 0; else sum[cur] = lmin[cur] = -1, lmax[cur] = 0; return ; } build(ls, x, mid); build(rs, mid + 1, y); update(cur); } void query(int cur, int x, int y, int s, int t, int &min, int &ss) { int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1; if(x >= s && y <= t) { if(ss + lmin[cur] < min) min = ss + lmin[cur]; ss += sum[cur]; return ; } pushdown(cur, x, y); if(mid >= s) query(ls, x, mid, s, t, min, ss); if(mid + 1 <= t) query(rs, mid + 1, y, s, t, min, ss); } void refresh(int cur, int x, int y, int s, int t, int c) { int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1; if(x >= s && y <= t) { to[cur] = c, rev[cur] = 0; if(c) sum[cur] = lmax[cur] = y - x + 1, lmin[cur] = 0; else sum[cur] = lmin[cur] = -(y - x + 1), lmax[cur] = 0; return ; } pushdown(cur, x, y); if(mid >= s) refresh(ls, x, mid, s, t, c); if(mid + 1 <= t) refresh(rs, mid + 1, y, s, t, c); update(cur); } void Reverse(int cur, int x, int y, int s, int t) { int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1; if(x >= s && y <= t) { rev[cur] ^= 1; sum[cur] = -sum[cur], Swap(lmin[cur], lmax[cur]); return ; } pushdown(cur, x, y); if(mid >= s) Reverse(ls, x, mid, s, t); if(mid + 1 <= t) Reverse(rs, mid + 1, y, s, t); update(cur); } void solve() { int i, q, x, y, min, ss; char ch[10]; scanf("%d", &q); for(i = 0; i < q; i ++) { scanf("%s%d%d", ch, &x, &y); if(ch[0] == 's') { scanf("%s", ch); refresh(1, 0, N - 1, x, y, ch[0] == '(' ? 1 : 0); } else if(ch[0] == 'r') Reverse(1, 0, N - 1, x, y); else { min = ss = 0; query(1, 0, N - 1, x, y, min, ss); if(ss == 0 && min == 0) printf("YES\n"); else printf("NO\n"); } } } void init() { scanf("%d", &N); scanf("%s", b); build(1, 0, N - 1); } int main() { int t, tt; scanf("%d", &t); for(tt = 0; tt < t; tt ++) { init(); printf("Case %d:\n", tt + 1); solve(); printf("\n"); } return 0; }