题目大意:
就是对于一个由'('和')‘组成的括号序列, 现在又3种操作, 第一种是将某个区间的所有括号修改成'('或者')', 第二种是将某个区间的所有字符反向'('变成')', ')'变成'(', 第三种是询问某个区间中的括号序列是否是一个号的序列
定义好的序列:
1.空序列是好序列
2.如果A是好序列那么'(' + A + ')'也是好序列
3. 如果A, B是好序列那么A + B也是好序列
大致思路:
考虑用线段树维护的时候, 两个序列的合并问题
注意到一个序列是好序列, 如果我们用1表示'(', -1表示')'那么
从左边开始前缀和都不能小于0, 且到结尾和为0的序列是好序列
于是考虑维护前缀和最小值和区间和这两个值, 但是当出现reverse操作时会发现只考这两个值是不够的, 还需要前缀和的最大值, 每次反转之后前缀和最小值是原来最大值的相反数, 前缀和最大值时原来最小值的相反数, 总和是原来总和的相反数
那么在更新的时候两个节点向上合并的转移也就很简单了
考虑区间修改操作, 两种操作和异或+覆盖很像, 需要用两个懒惰标记且覆盖标记优先级高于异或标记, 那么这个题到这里思路就很明显了
代码如下:
Result : Accepted Memory : 6216 KB Time : 262 ms
/* * Author: Gatevin * Created Time: 2015/8/19 22:14:32 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define maxn 100010 struct Segment_Tree { #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 struct State { int min, max, all; State(int _mi, int _ma, int _al) { min = _mi, max = _ma, all = _al; } State(){} }; State s[maxn << 2]; int cover[maxn << 2]; int rev[maxn << 2]; char in[maxn]; void pushUp(int rt) { s[rt] = State(min(s[rt << 1].min, s[rt << 1].all + s[rt << 1 | 1].min), max(s[rt << 1].max, s[rt << 1].all + s[rt << 1 | 1].max), s[rt << 1].all + s[rt << 1 | 1].all); return; } void pushDown(int l, int r, int rt, int mid) { if(cover[rt] != -1) { cover[rt << 1] = cover[rt << 1 | 1] = cover[rt]; if(cover[rt] == 1)//change to '(' { s[rt << 1] = State(1, mid - l + 1, mid - l + 1); s[rt << 1 | 1] = State(1, r - mid, r - mid); } else { s[rt << 1] = State(-(mid - l + 1), -1, -(mid - l + 1)); s[rt << 1 | 1] = State(-(r - mid), -1, -(r - mid)); } rev[rt << 1] = rev[rt << 1 | 1] = 0; cover[rt] = -1; } if(rev[rt]) { if(cover[rt << 1] != -1) cover[rt << 1] ^= rev[rt]; else rev[rt << 1] ^= rev[rt]; if(cover[rt << 1 | 1] != -1) cover[rt << 1 | 1] ^= rev[rt]; else rev[rt << 1 | 1] ^= rev[rt]; s[rt << 1] = State(-s[rt << 1].max, -s[rt << 1].min, -s[rt << 1].all); s[rt << 1 | 1] = State(-s[rt << 1 | 1].max, -s[rt << 1 | 1].min, -s[rt << 1 | 1].all); rev[rt] = 0; } return; } void build(int l, int r, int rt) { cover[rt] = -1; rev[rt] = 0; if(l == r) { if(in[l] == '(') s[rt] = State(1, 1, 1); if(in[l] == ')') s[rt] = State(-1, -1, -1); return; } int mid = (l + r) >> 1; build(lson); build(rson); pushUp(rt); } void update(int l, int r, int rt, int L, int R, int value)//change to value { if(l >= L && r <= R) { rev[rt] = 0; cover[rt] = value; if(value == 1) s[rt] = State(1, r - l + 1, r - l + 1); else s[rt] = State(-(r - l + 1), -1, -(r - l + 1)); return; } int mid = (l + r) >> 1; pushDown(l, r, rt, mid); if(mid >= L) update(lson, L, R, value); if(mid + 1 <= R) update(rson, L, R, value); pushUp(rt); return; } void update(int l, int r, int rt, int L, int R)//reverse { if(l >= L && r <= R) { if(cover[rt] != -1) cover[rt] ^= 1; else rev[rt] ^= 1; s[rt] = State(-s[rt].max, -s[rt].min, -s[rt].all); return; } int mid = (l + r) >> 1; pushDown(l, r, rt, mid); if(mid >= L) update(lson, L, R); if(mid + 1 <= R) update(rson, L, R); pushUp(rt); return; } State query(int l, int r, int rt, int L, int R) { if(l >= L && r <= R) return s[rt]; int mid = (l + r) >> 1; pushDown(l, r, rt, mid); State s1, s2; bool fl = 0, fr = 0; if(mid >= L) s1 = query(lson, L, R), fl = 1; if(mid + 1 <= R) s2 = query(rson, L, R), fr = 1; if(!fl) return s2; if(!fr) return s1; return State(min(s1.min, s1.all + s2.min), max(s1.max, s1.all + s2.max), s1.all + s2.all); } void solve() { int n, Q; scanf("%d", &n); scanf("%s", in); build(0, n - 1, 1); scanf("%d", &Q); char op[100], c[4]; int l, r; State ret; while(Q--) { scanf("%s", op); switch(op[0]) { case 'q': scanf("%d %d", &l, &r); ret = query(0, n - 1, 1, l, r); printf("%s\n", (ret.min >= 0 && ret.all == 0) ? "YES" : "NO"); break; case 's': scanf("%d %d %s", &l, &r, c); update(0, n - 1, 1, l, r, c[0] == '(' ? 1 : 0); break; case 'r': scanf("%d %d", &l, &r); update(0, n - 1, 1, l, r); break; } } puts(""); return; } }; Segment_Tree ST; int main() { int T; scanf("%d", &T); for(int cas = 1; cas <= T; cas++) { printf("Case %d:\n", cas); ST.solve(); } return 0; }