维护一个长度为 N 的小括号序列,实现两个操作:①将第 i 个位置的括号取反;②测试当前序列是否合法。
线段树维护两个变量:①区间内没有匹配的左括号数;②区间内没有匹配的右括号数。当这个区间的这两个变量都为 0 时序列合法。
/*
Author: JDD
PROG: spoj61.Brackets
DATE: 2015.12.07
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_N = 30005;
struct node{
int l, r, lx, rx;
}a[MAX_N << 2];
int n, m;
char s[MAX_N];
void update(int i)
{
int t1 = i << 1, t2 = t1 | 1;
a[i].lx = a[t1].lx + a[t2].lx - min(a[t1].lx, a[t2].rx);
a[i].rx = a[t1].rx + a[t2].rx - min(a[t1].lx, a[t2].rx);
}
void make_tree(int i, int l, int r)
{
a[i].l = l; a[i].r = r; a[i].lx = a[i].rx = 0;
if (l == r){
if (s[l] == '(') a[i].lx = 1;
else a[i].rx = 1;
return;
}
int mid = (a[i].l + a[i].r) >> 1, t1 = i << 1, t2 = t1 | 1;
make_tree(t1, l, mid); make_tree(t2, mid + 1, r);
update(i);
}
void tree_change(int i, int x)
{
if (a[i].l == a[i].r){
a[i].lx ^= 1; a[i].rx ^= 1; return;
}
int mid = (a[i].l + a[i].r) >> 1, t1 = i << 1, t2 = t1 | 1;
if (x <= mid) tree_change(t1, x);
else tree_change(t2, x);
update(i);
}
void init()
{
scanf("%s", s + 1);
make_tree(1, 1, n);
}
void doit()
{
scanf("%d", &m);
for (int i = 1; i <= m; i ++){
int x; scanf("%d", &x);
if (!x){
if (a[1].lx || a[1].rx) printf("NO\n");
else printf("YES\n");
} else tree_change(1, x);
}
}
int main()
{
int tot = 0;
while (scanf("%d", &n) != EOF){
printf("Test %d:\n", ++ tot);
init();
doit();
}
return 0;
}