题意:给定一个括号序列,可以对它进行set,对把一定范围内的括号变成某一种括号,reverse把左右括号互换,query一定范围内的括号序列是否合法。
做法:一开始的想法,节点记录未匹配的左右括号数,然后进行操作,因为小看了reverse操作(本来以为简单的把左右括号的值改一下就好了,可是...),WA。
然后百度大神,重要发现了一个好算法。
造成一我错 的原因是无法准确找的无法配对的右括号。造成右括号无法配对的原因是,右括号没有足够的最括号,所以,大神把左括号设为1,右括号为-1,这样从左到右计算,节点中值的最小值,这个最小值为0就可能完全匹配,但不一定(只是解决了右括号问题),而且再也不怕reverse了
#include<cstdio> #include<cstring> #define left l,m,x<<1 #define right m+1,r,x<<1|1 const int LMT=100003; int cov[LMT<<2],ox[LMT<<2],sum[LMT<<2],mxsum[LMT<<2],misum[LMT<<2]; char sec[LMT]; inline int max(int a,int b) { return a>b?a:b; } inline int min(int a,int b) { return a<b?a:b; } void ope(int op,int l,int r,int x) { cov[x]=op; mxsum[x]=op==1?r-l+1:0; misum[x]=op==-1?-r+l-1:0; sum[x]=(r-l+1)*op; ox[x]=0; } void fox(int x) { if(cov[x]) { cov[x]*=-1; sum[x]*=-1; ox[x]=0; } else { ox[x]^=1; sum[x]*=-1; } int t=mxsum[x]; mxsum[x]=-misum[x]; misum[x]=-t; } void cut(int l,int r,int x) { int m=(l+r)>>1; if(cov[x]) { ope(cov[x],left); ope(cov[x],right); cov[x]=0; } if(ox[x]) { fox(x<<1);fox(x<<1|1); ox[x]=0; } } void pushup(int x) { sum[x]=sum[x<<1]+sum[x<<1|1]; misum[x]=min(misum[x<<1],sum[x<<1]+misum[x<<1|1]); mxsum[x]=max(mxsum[x<<1],mxsum[x<<1|1]+sum[x<<1]); /******* MAXsum其实只是为了在翻转的时候用翻转的时候,以前不相和的括号就会相合, 这里的maxsum[x<<1|1]+sum[x<<1]提前做了这一步。 ****/ } void update(int op,int L,int R,int l,int r,int x) { if(L<=l&&r<=R) { if(op==-1) { ope(-1,l,r,x); ox[x]=0; } if(op==1) { ope(1,l,r,x); ox[x]=0; } if(op==2)fox(x); return; } cut(l,r,x); int m=(l+r)>>1; if(L<=m)update(op,L,R,left); if(R>m)update(op,L,R,right); pushup(x); } void query(int &mi,int &all,int L,int R,int l,int r,int x) { if(L<=l&&r<=R) { mi=misum[x]; all=sum[x]; return; } cut(l,r,x); int m=(l+r)>>1,mi1=0,mi2=0,al1=0,al2=0; if(L<=m)query(mi1,al1,L,R,left); if(R>m)query(mi2,al2,L,R,right); all=al1+al2; mi=min(mi1,al1+mi2); } void init() { memset(cov,0,sizeof(cov)); memset(ox,0,sizeof(ox)); memset(sum,0,sizeof(sum)); memset(misum,0,sizeof(misum)); memset(mxsum,0,sizeof(mxsum)); } int main(void) { int i,n,T,m,l,r,all,mi,I=1; char ord[10],op; scanf("%d",&T); while(T--) { init(); scanf("%d%s",&n,sec); for(i=0;sec[i];i++) { if(sec[i]=='(') update(1,i,i,0,n-1,1); else update(-1,i,i,0,n-1,1); } scanf("%d",&m); printf("Case %d:\n",I++); while(m--) { scanf("%s",ord); if(!strcmp(ord,"query")) { scanf("%d%d",&l,&r); mi=all=0; query(mi,all,l,r,0,n-1,1); if(mi==0&&all==0)puts("YES"); else puts("NO"); } if(!strcmp(ord,"set")) { scanf("%d%d",&l,&r); op=getchar(); while(op!='('&&op!=')')op=getchar(); if(op=='(')update(1,l,r,0,n-1,1); else update(-1,l,r,0,n-1,1); } if(!strcmp(ord,"reverse")) { scanf("%d%d",&l,&r); update(2,l,r,0,n-1,1); } } printf("\n"); } return 0; }