Topic link: http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809
Input
Output
For each question, output " Yes" if P remains balanced, or " No" otherwise.
Sample Input
4 2 (()) 1 3 2 3 2 1 () 1 2
Sample Output
No Yes No
Title:
Now give a string of parentheses of length n, guaranteed to be a balanced string of parentheses;
Then give q queries, each query has two values a, b, representing the query to exchange P[a] and P[b], will the bracket string become unbalanced.
answer:
First, we define a preSum array, which represents the prefix sum of the bracket sequence. When a '(' is encountered, 1 is added, and when a ')' is encountered, 1 is subtracted;
In this way, the bracket sequence is a balanced sequence $\Leftrightarrow$ preSum[n]==0, and preSum[i]≥0 for $\forall$i=1~n;
Then we have the following three cases:
- P[a]==P[b], this situation is obviously no different from the original exchange, and it is obviously balanced;
- P[a]=')' and P[b]='(', in this case, preSum[1]~preSum[a-1] will not change, preSum[a]~preSum[b-1 ] will be $+=2$, and preSum[b]~preSum[n] will not change. In this way, the new bracket sequence generated after the exchange still satisfies preSum[n]==0, and for $ \forall$i=1~n all have preSum[i]≥0, then obviously the bracket sequence is still a balanced sequence;
- P[a]='('and P[b]=')', in this case, preSum[1]~preSum[a-1] will not change, preSum[a]~preSum[b-1 ] will be $-=2$, and preSum[b]~preSum[n] will not change, so obviously the key lies in preSum[a]~preSum[b-1], we know that once there is a preSum[i ]<0, this bracket sequence is unbalanced, so we must ensure that preSum[a]~preSum[b-1] are all greater than or equal to 2.
Therefore, we can use the segment tree or RMQ to maintain the minimum value of the preSum[] array. For each query, we only need to find out whether the minimum value of preSum[i] in the interval [a, b] is greater than 2.
AC code:
①Line segment tree:
#include<cstdio> #include<cstring> #include<vector> using namespace std; typedef long long LL; const int maxn=1e5+10; const int INF=0x3f3f3f3f; int n,q; char str[maxn]; int preSum[maxn]; struct Node{ int l,r; int val; }node[4*maxn]; void pushup(int root) { node[root].val =min(node[root* 2 ].val,node[root* 2 + 1 ].val); } void build(int root,int l,int r) { node[root].l=l; node[root].r=r; if(l==r) node[root].val=preSum[l]; else { int mid=l+(r-l)/2; build(root*2,l,mid); build(root*2+1,mid+1,r); pushup(root); } } int query(int root,int st,int ed) { if(ed<node[root].l || node[root].r<st) return INF; if(st<=node[root].l && node[root].r<=ed) return node[root].val; else return min(query(root*2,st,ed),query(root*2+1,st,ed)); } intmain () { while(scanf("%d%d",&n,&q)!=EOF) { scanf("%s",str+1); preSum[0]=0; for(int i=1;i<=n;i++) preSum[i]=preSum[i-1]+(str[i]=='('?1:-1); build(1,1,n); for(int i=1,a,b;i<=q;i++) { scanf("%d%d",&a,&b); if(a>b) swap(a,b); if( str[a]==str[b] || (str[a]==')' && str[b]=='(') ) printf("Yes\n"); else if(query(1,a,b-1)>=2) printf("Yes\n"); else printf("No\n"); } } }
②RMQ:
#include<cstdio> #include<cstring> #include<vector> #include<cmath> using namespace std; typedef long long LL; const int maxn=1e5+10; const int INF=0x3f3f3f3f; int n,q; char str[maxn]; int preSum[maxn]; struct _RMQ{ int Mnum[maxn][20]; //int(log(maxn)/log(2.0)) void init(int num[]) { for(int i=1;i<=n;i++) Mnum[i][0]=num[i]; int j_max=(log(n)/log(2)); for(int j=1;j<=j_max;j++) { for(int i=1;i<=n;i++) { if(i+(1<<j)-1 <= n) Mnum[i][j]=min(Mnum[i][j-1],Mnum[i+(1<<(j-1))][j-1]); } } } int query(int l,int r) { int k=log(r-l+1)/log(2); return min(Mnum[l][k],Mnum[r-(1<<k)+1][k]); } }RMQ; intmain () { while(scanf("%d%d",&n,&q)!=EOF) { scanf("%s",str+1); preSum[0]=0; for(int i=1;i<=n;i++) preSum[i]=preSum[i-1]+(str[i]=='('?1:-1); RMQ.init(preSum); for(int i=1,a,b;i<=q;i++) { scanf("%d%d",&a,&b); if(a>b) swap(a,b); if( str[a]==str[b] || (str[a]==')' && str[b]=='(') ) printf("Yes\n"); else if(RMQ.query(a,b-1)>=2) printf("Yes\n"); else printf("No\n"); } } }