csu 1809 Parenthesis(线段树)
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; char s[maxn]; int pre[maxn],Min[maxn<<2]; int n,q,u,v; /* 给一个长度为n(<=1e5)的只有()的匹配字符串,q(<=1e5)次询问 每次询问在原串上交换两个字符,问交换之后是否还是合法子串 如果把(值为1,)值为-1,那么一个区间前缀和不存在<0,并且 最终的和为0,肯定就是一个匹配字符串 那么交换的两个字符是相同的,肯定是合法的 如果交换的是 )(,那么肯定也是合法的 如果交换的是(),那么就要考虑[l,r)之间在交换后是否会产生 负数,交换的结果是,[l,r)都会-2,那么求[l,r)之间的最小值 写个线段树就好了 */ void build(int rt,int l,int r){ if(l==r){ Min[rt]=pre[l]; return ; } int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } int query(int rt,int l,int r,int ql,int qr){ if(ql<=l&&qr>=r)return Min[rt]; int mid=(l+r)>>1; int res=INT_MAX; if(ql<=mid)res=min(res,query(rt<<1,l,mid,ql,qr)); if(qr>mid)res=min(res,query(rt<<1|1,mid+1,r,ql,qr)); return res; } int main(){ int n,q,u,v; while(~scanf("%d%d",&n,&q)){ getchar();gets(s); for(int i=1;i<=n;i++){ if(s[i-1]=='(')pre[i]=1; else pre[i]=-1; pre[i]+=pre[i-1]; } build(1,1,n); while(q--){ scanf("%d%d",&u,&v); if(u>v)swap(u,v); if(s[u-1]==s[v-1])puts("Yes"); else if(s[v-1]=='(')puts("Yes"); else{ int a=query(1,1,n,u,v-1); if(a>1)puts("Yes"); else puts("No"); } } } return 0; }