题目链接: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;
}