P8765 [蓝桥杯 2021 国 AB] 翻转括号序列

· · 题解

比较基础的线段树板子。

若用 1 表示左括号,-1 表示右括号,求原串的前缀和 sum_i,考虑 [l,r] 为合法括号序列的条件:

1.sum_{l-1}=sum_r

2.对于任意 i 满足 l\le i\le r,有 sum_{l-1}\le sum_i

考虑式二可以用区间最小值维护,且满足单调性,于是想到线段树 + 二分。

满足式二以后,只要找到解集中最右一个满足式一的即可。

如果 sum_{l-1}\le sum_i<sum_{l-1}+1sum_i\in\mathbb{Z},则 sum_{l-1}=sum_i

因此式一也满足单调性,这样先在 x 向右二分式二,再在式二最大取值向左二分式一,就可以处理询问了。

那么,如何处理修改操作呢?

考虑如果要把一个区间 [l,r] 取反,完全可以分成 [1,l-1][1,r] 分别取反。

这样就可以分成两个左端点为 1 的区间,于是可以用上面的前缀和维护了。

具体来说,将 [1,x] 取反的代价为:

前者影响了最小值,所以再维护一个最大值,每次先交换最大和最小值再取反。 后者中,单点查询 $sum_x$,然后用懒惰标记处理区间加就行。 总体复杂度 $\operatorname{O}(m\times\log n)$。 ------------ 码量还行吧(可能线段树本身长),基本就板子。 ```cpp #include<bits/stdc++.h> using namespace std; const int maxn=1e6+84; const int maxt=5e6+84; int n,m,op,x,y,ans,slast,qzh[maxn]; char s[maxn]; struct Point{ int l,r,miin,maax,lazy_swap,lazy_add; }; struct Tree{ Point T[maxt]; inline void pushup(int x){ T[x].maax=max(T[x<<1].maax,T[x<<1|1].maax); T[x].miin=min(T[x<<1].miin,T[x<<1|1].miin); return ; } inline void swp(int x){ swap(T[x].maax,T[x].miin); T[x].maax*=-1; T[x].miin*=-1; T[x].lazy_add*=-1; T[x].lazy_swap^=1; return ; } inline void addd(int x,int val){ T[x].miin+=val; T[x].maax+=val; T[x].lazy_add+=val; return ; } inline void pushdown(int x){ if(T[x].lazy_swap){ swp(x<<1); swp(x<<1|1); T[x].lazy_swap=0; } if(T[x].lazy_add){ addd(x<<1,T[x].lazy_add); addd(x<<1|1,T[x].lazy_add); T[x].lazy_add=0; } return ; } inline void init(int id,int l,int r){ T[id].l=l; T[id].r=r; if(l==r){ T[id].maax=T[id].miin=qzh[l]; return ; } int mid=l+r>>1; init(id<<1,l,mid); init(id<<1|1,mid+1,r); pushup(id); return ; } inline void add(int id,int l,int r,int val){ if(l<=T[id].l&&T[id].r<=r){ addd(id,val); return ; } pushdown(id); int mid=T[id].l+T[id].r>>1; if(l<=mid) add(id<<1,l,r,val); if(mid<r) add(id<<1|1,l,r,val); pushup(id); return ; } inline void swapp(int id,int l,int r){ if(l<=T[id].l&&T[id].r<=r){ swp(id); return ; } pushdown(id); int mid=T[id].l+T[id].r>>1; if(l<=mid) swapp(id<<1,l,r); if(mid<r) swapp(id<<1|1,l,r); pushup(id); return ; } inline int query_p(int id,int pos){ if(!pos) return 0; if(T[id].l==T[id].r) return T[id].maax; pushdown(id); int mid=T[id].l+T[id].r>>1; if(pos<=mid) return query_p(id<<1,pos); return query_p(id<<1|1,pos); } inline void modify(int x){ if(!x) return ; if(x<n) add(1,x+1,n,-query_p(1,x)*2); swapp(1,1,x); return ; } inline int bsy(int id,int x,int val){ if(T[id].l==T[id].r) return T[id].l; pushdown(id); int anss=n+1,mid=T[id].l+T[id].r>>1; if(T[id<<1].miin<val&&x<=mid) anss=bsy(id<<1,x,val); if(anss!=n+1) return anss; if(T[id<<1|1].miin<val) anss=bsy(id<<1|1,x,val); return anss; } inline int bsz(int id,int x,int val){ if(T[id].l==T[id].r) return T[id].l; pushdown(id); int anss=-168,mid=T[id].l+T[id].r>>1; if(T[id<<1|1].miin<val&&x>mid) anss=bsz(id<<1|1,x,val); if(anss>0) return anss; if(T[id].miin<val) anss=bsz(id<<1,x,val); return anss; } inline int anser(int x){ slast=query_p(1,x-1); ans=bsz(1,bsy(1,x,slast)-1,slast+1); return ans>x?ans:0; } }Sherry; inline int mp(char c){ return c=='('?1:-1; } int main(){ scanf("%d%d",&n,&m); scanf("%s",s+1); for(int i=1;i<=n;i++) qzh[i]=qzh[i-1]+mp(s[i]); Sherry.init(1,1,n); while(m--){ scanf("%d%d",&op,&x); if(op==2){ printf("%d Sherry\n",Sherry.anser(x)); continue; } scanf("%d",&y); Sherry.modify(y); Sherry.modify(x-1); } return 0; } ```