题目链接:https://ac.nowcoder.com/acm/contest/5795/L
给你长度为n的一个扩号序列。m次修改,每次修改把第x个扩号取反方向。并且修改后询问扩号序列是否合法。
思路:用一个线段树维护这个扩号序列
'(':-1
')':1
每次修改其实就是一个单点修改。如果前缀和<0那么就不合法。如果前缀和>0并且1-n的和为0就合法。
#include <bits/stdc++.h>
using namespace std;
char s[100005];
int sum[4*100005], mi[4*100005];
void gx(int i, int l, int r, int x, int y){
if(l==r){
sum[i]=y; return ;
}
if(x<=(l+r)/2) gx(i<<1, l, l+r>>1, x, y);
else gx(i<<1|1, (l+r>>1)+1, r, x, y);
sum[i]=sum[i<<1]+sum[i<<1|1];
mi[i]=min(mi[i<<1], mi[i<<1|1]+sum[i<<1]);//维护前缀最小值
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
scanf("%s", s+1);
for(int i=1; i<=n; i++){
if(s[i]=='(') gx(1, 1, n, i, 1);
else gx(1, 1, n, i, -1);
}
while(m--){
int x; scanf("%d", &x);
if(s[x]=='('){
gx(1, 1, n, x, -1); s[x]=')';
}
else{
gx(1, 1, n, x, 1); s[x]='(';
}
if(sum[1]==0&&mi[1]>=0){
printf("Yes\n");
}
else{
printf("No\n");
}
}
return 0;
}

京公网安备 11010502036488号