Yet Another Bracket Sequence(线段树&前缀和)

传送门
思路:线段树维护最小前缀和。令 ′ ( ′ '(' (为1, ′ ) ′ ')' ) − 1 -1 1。保证前 n n n项和为0且前 n n n项最小前缀和大于等于0即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
struct node{
	int s,l,r,lz;
}a[N<<2];/// a[x].s 表示 以区间[a[x].l,a[x].r]为下标的最小前缀和. 
int pre[N],n,m,sum;
char s[N];
void re(int x){
	a[x].s=min(a[x<<1].s,a[x<<1|1].s);
}
void push_down(int x){
	 if(!a[x].lz) return;
	 a[x<<1].lz+=a[x].lz,a[x<<1|1].lz+=a[x].lz;
	 a[x<<1].s+=a[x].lz,a[x<<1|1].s+=a[x].lz;
	 a[x].lz=0; 
}
void build(int x,int l,int r){
	a[x].l=l,a[x].r=r;
	if(l==r){
		a[x].s=pre[l];
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	re(x);
} 
void change(int x,int l,int r,int val){
	if(a[x].l>=l&&a[x].r<=r){
		a[x].s+=val;
		a[x].lz+=val;
		return ;
	}
	push_down(x);
	int mid=(a[x].l+a[x].r)>>1;
	if(l<=mid) change(x<<1,l,r,val);
	if(r>mid) change(x<<1|1,l,r,val);
	re(x);
}
int main(){
	scanf("%d%d%s",&n,&m,s+1);
	for(int i=1;i<=n;i++) pre[i]=pre[i-1]+((s[i]=='(')?1:-1);
	sum=pre[n];
	build(1,1,n);
	while(m--){
		int x;
		scanf("%d",&x);
		if(s[x]=='(')  s[x]=')',change(1,x,n,-2),sum-=2;
		else s[x]='(',change(1,x,n,2),sum+=2;
		if(a[1].s>=0&&sum==0) puts("Yes");
		else puts("No");
	}
	return 0;
}