[HNOI2011]括號修復 / [JSOI2011]括號序列
阿新 • • 發佈:2018-12-20
tchar efi oid -- == wap bits http gis
傳送門
Solution
一道題花費了兩天的時間……
在大佬
@PinkRabbit
的幫助下,終於AC了,感動……首先,我們考慮一個括號序列被修改成合法序列需要的次數:
- 我們需要修改的其實是形如
...)))))(((((...
- 我們把
(
看成是-1,把)
看成是1,那麽其實只要知道了區間的前綴最大值pr
和後綴最小值`sum-pr那麽就有\[ans=\left \lceil \frac{pr}{2} \right \rceil+\left \lceil \frac{-sum+su}{2} \right \rceil\]
如果我們維護了區間的前綴最大值
pr
和後綴最大值su
和區間和sum
- 區間翻轉:
swap(pr,su)
- 區間反轉:
pr=-(sum-su)
同時su=-(sum-pr)
,這裏的(sum-su)
就是前綴最小值,因為區間取了反,所以就是前綴最大值啦- 區間覆蓋:直接打標記
所有區間操作都可以用平衡樹來實現
要註意:區間覆蓋的優先級應大於另外兩個操作
Code?
#include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } #define MN 100005 char s[MN]; class fhq { private: int sz; int pri[MN],ls[MN],rs[MN],siz[MN]; int pr[MN],su[MN],tt[MN],cover[MN],V[MN]; bool rev[MN],inv[MN]; inline unsigned int random() { static unsigned int x=23333; return x^=x<<13,x^=x>>17,x^=x<<5; } inline void up(int x) { siz[x]=1+siz[ls[x]]+siz[rs[x]]; tt[x]=tt[ls[x]]+tt[rs[x]]+V[x]; pr[x]=max(pr[ls[x]],tt[ls[x]]+V[x]+pr[rs[x]]); su[x]=max(su[rs[x]],tt[rs[x]]+V[x]+su[ls[x]]); } inline void update(int x,int opt) { if(!x) return; if(opt==1) { std::swap(pr[x],su[x]);std::swap(ls[x],rs[x]); rev[ls[x]]^=1;rev[rs[x]]^=1; } if(opt==2) { V[x]=-V[x]; pr[x]=-(tt[x]-pr[x]);su[x]=-(tt[x]-su[x]); std::swap(pr[x],su[x]); tt[x]=-tt[x]; inv[ls[x]]^=1;inv[rs[x]]^=1; } if(opt==3) { V[x]=cover[x];tt[x]=cover[x]*siz[x]; su[x]=max(0,tt[x]);pr[x]=max(0,tt[x]); cover[ls[x]]=cover[rs[x]]=cover[x]; rev[ls[x]]=inv[ls[x]]=0; rev[rs[x]]=inv[rs[x]]=0; } } inline void down(int x) { if(cover[x]) update(ls[x],3),update(rs[x],3),cover[x]=0; if(rev[x]) update(ls[x],1),update(rs[x],1),rev[x]=0; if(inv[x]) update(ls[x],2),update(rs[x],2),inv[x]=0; } public: int rt; int Merge(int rt1,int rt2) { if(!rt1||!rt2) return rt2|rt1; if(pri[rt1]<pri[rt2]) { down(rt1),rs[rt1]=Merge(rs[rt1],rt2); up(rt1);return rt1; } else { down(rt2),ls[rt2]=Merge(rt1,ls[rt2]); up(rt2);return rt2; } } void Split(int x,int k,int&rt1,int&rt2) { if(!x) return (void)(rt1=rt2=0); down(x); if(k<=siz[ls[x]]) { Split(ls[x],k,rt1,rt2); ls[x]=rt2;up(x);rt2=x; } else { Split(rs[x],k-siz[ls[x]]-1,rt1,rt2); rs[x]=rt1;up(x);rt1=x; } } void Build(int &x,int l,int r) { if(l>r) return;int mid=l+r>>1; x=++sz; V[x]=tt[x]=(s[mid]==')'?1:-1),pri[x]=random(); if(l==r) return(void)(pr[x]=su[x]=max(0,V[x]),siz[x]=1); Build(ls[x],l,mid-1),Build(rs[x],mid+1,r);up(x); } void Reverse(int l,int r) { register int rt1,rt2,rt3,rt4; Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4); rev[rt3]^=1;update(rt3,1);rt=Merge(rt1,Merge(rt3,rt4)); } void Invert(int l,int r) { register int rt1,rt2,rt3,rt4; Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4); inv[rt3]^=1;update(rt3,2);rt=Merge(rt1,Merge(rt3,rt4)); } void Replace(int l,int r,int c) { register int rt1,rt2,rt3,rt4; Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4); cover[rt3]=c,update(rt3,3);rev[rt3]=inv[rt3]=0;rt=Merge(rt1,Merge(rt3,rt4)); } int Query(int l,int r) { register int rt1,rt2,rt3,rt4,ret; Split(rt,l-1,rt1,rt2); Split(rt2,r-l+1,rt3,rt4); ret=(pr[rt3]+1)/2+(-tt[rt3]+pr[rt3]+1)/2; rt=Merge(rt1,Merge(rt3,rt4)); return ret; } }T; int main(){ register int n,m,l,r; n=read(),m=read(); scanf("%s",s+1);T.Build(T.rt,1,n); register char opt[10],c[2]; while(m--) { scanf("%s",opt+1);l=read(),r=read(); if(opt[1]=='R') scanf("%s",c),T.Replace(l,r,c[0]=='('?-1:1); if(opt[1]=='S') T.Reverse(l,r); if(opt[1]=='I') T.Invert(l,r); if(opt[1]=='Q') printf("%d\n",T.Query(l,r)); } return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!
[HNOI2011]括號修復 / [JSOI2011]括號序列