题目大意
给定一个括号序列,支持一下以下三种操作:
1、set l r c: 把区间 [l,r]内的所有元素全部改成 c(c是’(’或者’)’)
2、reverse l r: 把区间[l,r]内的所以元素全部取反
3、query l,r: 查询区间 [l,r] 括号序列是否合法
题解
把左括号当成-1,右括号当成1,如果括号序列合法,则区间和为0,并且任意前缀和会小于等于0,当然我们不需要判断所有的前缀和是否都小于等于0,只需要维护一个前缀和最大值即可,只要前缀和最大值小于等于0,并且区间和为0,括号序列就是合法的,为了处理方便还额外增加一个域,前缀和的最小值,在进行取反操作的时候会方便很多,另外要注意set和reverse两种操作的顺序,顺序不同,结果也就不同,如果是set操作,则之前所有的标记都失效了,直接清除即可,但是如果有 set标记则进行取反,否则进行异或标记的取反操作
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define lson l,m,s<<1 #define rson m+1,r,s<<1|1 #define MAXN 100005 int setv[MAXN<<2],Xor[MAXN<<2],sumv[MAXN<<2],lmin[MAXN<<2],lmax[MAXN<<2]; char str[MAXN]; void PushUp(int s) { sumv[s]=sumv[s<<1]+sumv[s<<1|1]; lmax[s]=max(lmax[s<<1],sumv[s<<1]+lmax[s<<1|1]); lmin[s]=min(lmin[s<<1],sumv[s<<1]+lmin[s<<1|1]); } void Fxor(int s,int m) { int temp; if(setv[s]!=0) { if(setv[s]==1) setv[s]=-1; else setv[s]=1; if(setv[s]==1) { sumv[s]=m; lmax[s]=m; lmin[s]=0; } else { sumv[s]=-m; lmax[s]=0; lmin[s]=-m; } } else { Xor[s]^=1; sumv[s]=-sumv[s]; temp=lmax[s]; lmax[s]=-lmin[s]; lmin[s]=-temp; } } void PushDown(int s,int m) { if(setv[s]!=0) { setv[s<<1]=setv[s<<1|1]=setv[s]; Xor[s<<1]=Xor[s<<1|1]=0; if(setv[s]==1) { sumv[s<<1]=(m-(m>>1)); sumv[s<<1|1]=(m>>1); lmax[s<<1]=sumv[s<<1]; lmax[s<<1|1]=sumv[s<<1|1]; lmin[s<<1]=0; lmin[s<<1|1]=0; } else { sumv[s<<1]=-(m-(m>>1)); sumv[s<<1|1]=-(m>>1); lmin[s<<1]=-sumv[s<<1]; lmin[s<<1|1]=-sumv[s<<1|1]; lmax[s<<1]=0; lmax[s<<1|1]=0; } setv[s]=0; } if(Xor[s]) { Fxor(s<<1,m-(m>>1)); Fxor(s<<1|1,(m>>1)); Xor[s]=0; } } void build(int l,int r,int s) { setv[s]=0; Xor[s]=0; if(l==r) { if(str[l]=='(') sumv[s]=-1; else sumv[s]=1; lmax[s]=(sumv[s]>0)?1:0; lmin[s]=(sumv[s]<0)?-1:0; return; } int m=(l+r)>>1; build(lson); build(rson); PushUp(s); } void update(int ql,int qr,int d,int l,int r,int s) { if(ql<=l&&r<=qr) { if(d==-1) { setv[s]=-1; sumv[s]=-(r-l+1); lmax[s]=0; lmin[s]=sumv[s]; Xor[s]=0; } else if(d==1) { setv[s]=1; sumv[s]=r-l+1; lmax[s]=sumv[s]; lmin[s]=0; Xor[s]=0; } else Fxor(s,r-l+1); return; } PushDown(s,r-l+1); int m=(l+r)>>1; if(ql<=m) update(ql,qr,d,lson); if(qr>m) update(ql,qr,d,rson); PushUp(s); } int querya(int ql,int qr,int l,int r,int s) { if(ql<=l&&r<=qr) return sumv[s]; PushDown(s,r-l+1); int m=(l+r)>>1,ans=0; if(ql<=m) ans+=querya(ql,qr,lson); if(qr>m) ans+=querya(ql,qr,rson); return ans; } int queryb(int ql,int qr,int l,int r,int s) { if(ql<=l&&r<=qr) return lmax[s]; PushDown(s,r-l+1); int m=(l+r)>>1,ans; if(qr<=m) ans=queryb(ql,qr,lson); else if(ql>m) ans=queryb(ql,qr,rson); else ans=max(queryb(ql,qr,lson),querya(ql,qr,lson)+queryb(ql,qr,rson)); return ans; } int main(void) { int T,n,m,a,b,p=0; char op[1000],ch[100]; scanf("%d",&T); while(T--) { printf("Case %d:\n",++p); scanf("%d%s%d",&n,str,&m); build(0,n-1,1); while(m--) { scanf("%s",op); if(op[0]=='s') { scanf("%d%d%s",&a,&b,ch); if(ch[0]=='(') update(a,b,-1,0,n-1,1); else update(a,b,1,0,n-1,1); } else if(op[0]=='r') { scanf("%d%d",&a,&b); update(a,b,2,0,n-1,1); } else { scanf("%d%d",&a,&b); if(!querya(a,b,0,n-1,1)&&!queryb(a,b,0,n-1,1)) printf("YES\n"); else printf("NO\n"); } } printf("\n"); } return 0; }