题意:给定括号序列,让后m次修改,对于每次修改回答括号序列是否合法。
可以先想想暴力怎么搞,从头枚举,记一个cnt,碰到 ( 就 cnt++ ,碰到 ) 就cnt-- ,如果碰到cnt < 0 的情况,或者最后 cnt != 0,即为不合法。
照这个过程,用线段树来模拟一下就行了,发现每次 cnt-- 的时候,意为 ) 抵消掉了 ( ,那么线段树 pushup 的时候,左端区间的 ( 可以和右边区间的 ) 抵消,左端区间的 ) 和右端区间的 ( 都不能被抵消,那么直接加上即可,最后根节点的 ( ) 两个的数量都为 0 的时候即合法。
花里胡哨的做法。。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m;
string s;
struct Node
{
int l,r;
int a,b;
}tr[N<<2];
void pushup(int u)
{
if(tr[L].a>=tr[R].b) tr[u].a=tr[L].a-tr[R].b,tr[u].b=0;
else tr[u].a=0,tr[u].b=tr[R].b-tr[L].a;
tr[u].a+=tr[R].a,tr[u].b+=tr[L].b;
}
void build(int u,int l,int r)
{
tr[u]={l,r};
if(l==r)
{
tr[u].a=(s[l-1]=='(');
tr[u].b=(s[l-1]==')');
return;
}
build(L,l,Mid),build(R,Mid+1,r);
pushup(u);
}
void modify(int u,int l,int r)
{
if(tr[u].l==l&&tr[u].r==r)
{
tr[u].a^=1,tr[u].b^=1;
return;
}
if(l<=Mid) modify(L,l,r);
if(r>Mid) modify(R,l,r);
pushup(u);
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
cin>>n>>m>>s;
build(1,1,n);
while(m--)
{
int x;
scanf("%d",&x);
modify(1,x,x);
if(tr[1].a!=0||tr[1].b!=0) puts("No");
else puts("Yes");
}
return 0;
}
/*
*/