题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809

题意:给了一个平衡的括号序列s(平衡是指括号匹配正常) 现在q次询问,每次输入两个数a、b 问将s[a] s[b]交换后是

否任然平衡(即是否正常匹配),平衡则输出“Yes” 否则输出“No”

解法:粘贴了一段解题报告过来,原地址:这里

括号匹配问题的经典做法就是把序列转化成前缀和,‘(’就等于前一个+1,‘)’就等于后一个-1,所以正常的序列

的前缀和一定是>=0的.由于一开始序列是平衡的,那么,只有当s[l]==’(’ && s[r]==’)’时(l<=r)才有可能不平衡,并

且只会对前缀和val[i]产生影响的区间为val[l]~val[r-1],所以就可以用线段树来求val[l]~val[r-1]的最小值,如果val[l]

~val[r-1]的前缀和小于2的话就是No,因为s[l]==’(’ && s[r]==’)’就换后,val[l]~val[r-1]就会减少2.这题数据比较水,

看到一个学弟暴力for都过了。

#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
struct node{
    int l,r,mi;
}tree[maxn*4];
char s[maxn];
int a[maxn];
void build(int l, int r, int rt){
    tree[rt].l=l,tree[rt].r=r;
    if(l==r){
        tree[rt].mi=a[l];
        return;
    }
    int mid=l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tree[rt].mi=min(tree[rt*2].mi,tree[rt*2+1].mi);
}
int query(int L, int R, int rt){
    if(L==tree[rt].l&&tree[rt].r==R){
        return tree[rt].mi;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(R<=mid) return query(L,R,rt*2);
    else if(L>mid) return query(L,R,rt*2+1);
    else return min(query(L,mid,rt*2),query(mid+1,R,rt*2+1));
}
int main()
{
    int n,q;
    while(scanf("%d%d", &n,&q)!=EOF)
    {
        memset(a, 0, sizeof(a));
        scanf("%s", s+1);
        for(int i=1; i<=n; i++) a[i]=a[i-1]+(s[i]=='('?1:-1);
        build(1,n,1);
        while(q--){
            int l,r;
            scanf("%d%d",&l,&r);
            if(l>r) swap(l,r);
            if(s[l]=='('&&s[r]==')'){
                if(query(l,r-1,1)>=2){
                    puts("Yes");
                }
                else{
                    puts("No");
                }
            }
            else{
                puts("Yes");
            }
        }
    }
    return 0;
}