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