题解:P14761 [Opoi 2025] CCD 的序列

· · 题解

比较板的平衡树题,比 A 好想。

首先括号序列有个非常典的套路,就是将左括号设为 1,右括号设为 -1

合法就相当于前缀和的最小值 \ge 0,且序列总和 =0

然后插入操作是先插 1,再插 -1,所以保证了合法性。

鉴于有插入操作,考虑用平衡树维护整个串。

如果 l=r,相当于两个括号插在一块,正好匹配上,没有改变匹配的。

否则,设子串 [l+1,r] 中有 x 个未匹配的左括号,y 个未匹配的右括号。

则插入的左括号会使这 y 个未匹配的右括号在原串中匹配的左括号往前移一个,插入的右括号同理。

这时,原串匹配最靠里的未匹配左右括号的括号就没有能匹配的了,所以它们两个要匹配起来。

答案即为 2x+2y

代码如下。 ```cpp #include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define p_q priority_queue #define pb push_back #define mk make_pair #define pii pair<int,int> #define ve vector #define endl '\n' #define fi first #define se second #define INF 0x3f3f3f3f #define lowbit(x) (x&(-x)) namespace cute_fzj_kuai_ruarua{ int n; int ls[400005],rs[400005],cnt=0,key[400005],val[400005],siz[400005]; int sum[400005],lmn[400005],rmx[400005],root; void pushup(int x){ siz[x]=siz[ls[x]]+siz[rs[x]]+1; sum[x]=sum[ls[x]]+sum[rs[x]]+val[x]; if(!ls[x]&&!rs[x]){ lmn[x]=min(0,val[x]); rmx[x]=max(0,val[x]); }else{ lmn[x]=0; rmx[x]=0; } if(ls[x]){ lmn[x]=min(lmn[x],lmn[ls[x]]); lmn[x]=min(lmn[x],sum[ls[x]]+val[x]); rmx[x]=max(rmx[x],rmx[ls[x]]+val[x]+sum[rs[x]]); } if(rs[x]){ rmx[x]=max(rmx[x],rmx[rs[x]]); rmx[x]=max(rmx[x],sum[rs[x]]+val[x]); lmn[x]=min(lmn[x],sum[ls[x]]+val[x]+lmn[rs[x]]); } } int newnode(int x){ cnt++; val[cnt]=x; siz[cnt]=1; sum[cnt]=x; lmn[cnt]=min(0,x); rmx[cnt]=max(0,x); key[cnt]=rand(); return cnt; } void split(int x,int v,int &l,int &r){ if(!x){ l=0; r=0; return ; } if(siz[ls[x]]>=v){ r=x; split(ls[x],v,l,ls[x]); }else{ l=x; split(rs[x],v-siz[ls[x]]-1,rs[x],r); } pushup(x); } int merge(int x,int y){ if(!x||!y) return x|y; if(key[x]>key[y]){ rs[x]=merge(rs[x],y); pushup(x); return x; }else{ ls[y]=merge(x,ls[y]); pushup(y); return y; } } void debug(int x){ if(!x) return ; debug(ls[x]); if(x==root) cout<<"Root"; cout<<lmn[x]<<" "<<rmx[x]<<" "<<val[x]<<endl; debug(rs[x]); } void main(){ srand(time(0)); int n; cin>>n; while(n--){ int l,r; cin>>l>>r; int x,y,z; if(l==r){ split(root,l,x,y); cout<<0<<endl; root=merge(x,merge(merge(newnode(1),newnode(-1)),y)); // debug(root); continue; } split(root,r,y,z); split(y,l,x,y); root=y; // debug(y); cout<<2*(-lmn[y]+rmx[y])<<endl; root=merge(merge(x,newnode(1)),merge(y,merge(newnode(-1),z))); // debug(root); } } } using namespace cute_fzj_kuai_ruarua; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cute_fzj_kuai_ruarua::main(); return 0; } ```