BZOJ 2329: [HNOI2011]括号修复 Splay
Description
题解:
随便给定一个括号序列,最终一定能表示成 $..)))))))((((...$ 这种形式.
那么,这个时候答案就是左括号数量/2+右括号数量/2(都是向上取整)
所以,我们考虑用 $Splay$ 来维护这种情况下左括号和右括号的数量.
这里的那个 $swap$ 不是镜面翻转,所以在维护的时候要维护一个反串的数量.
而那个 $invert$ 可以看作是先 $swap$,再进行一个镜面翻转.
由于本题有多个标记,所以标记的下传顺序要定好.
我们发现,$invert$ 和 $swap$ 操作是互不干扰的,所以这两个的顺序无所谓.
而 $swap$ 操作和 $replace$ 操作也是互不干扰的.
而 $invert$ 操作会影响 $replace$ 操作.
所以在 $invert $ 的时候将 $replace$ 标记取反就好了.
#include <cstdio> #include <map> #include <vector> #include <cstring> #include <string> #include <algorithm> #define N 100007 #define ll long long #define lson s[x].ch[0] #define rson s[x].ch[1] using namespace std; char str[N]; int root,tot,A[N]; struct Splay { int ch[2],f,sum[2][2]; int swa,inv,tag,w,siz; }s[N]; // (->-1, )->+1 int get(int x) { return s[s[x].f].ch[1]==x; } void mark_swa(int x) { swap(lson,rson); swap(s[x].sum[0][0],s[x].sum[1][1]); swap(s[x].sum[0][1],s[x].sum[1][0]); s[x].swa^=1; } void mark_inv(int x) { s[x].w=-s[x].w; s[x].tag=-s[x].tag; swap(s[x].sum[0][0],s[x].sum[1][0]); swap(s[x].sum[0][1],s[x].sum[1][1]); s[x].inv^=1; } void mark_tag(int x,int v) { s[x].w=s[x].tag=v; if(v==1) { s[x].sum[0][0]=s[x].sum[1][1]=s[x].siz; s[x].sum[0][1]=s[x].sum[1][0]=0; } else { s[x].sum[0][1]=s[x].sum[1][0]=s[x].siz; s[x].sum[0][0]=s[x].sum[1][1]=0; } } void pushup(int x) { int l=lson,r=rson; s[x].siz=s[lson].siz+s[rson].siz+1; // 00 与 11,10 与 01 s[x].sum[0][0]=s[l].sum[0][0]+max(0,s[r].sum[0][0]-s[l].sum[0][1]+s[x].w); // ) s[x].sum[0][1]=s[r].sum[0][1]+max(0,s[l].sum[0][1]-s[r].sum[0][0]-s[x].w); // ( s[x].sum[1][0]=s[l].sum[1][0]+max(0,s[r].sum[1][0]-s[l].sum[1][1]-s[x].w); // ( s[x].sum[1][1]=s[r].sum[1][1]+max(0,s[l].sum[1][1]-s[r].sum[1][0]+s[x].w); // ) } void pushdown(int x) { if(s[x].swa) { if(lson) mark_swa(lson); if(rson) mark_swa(rson); s[x].swa=0; } if(s[x].inv) { if(lson) mark_inv(lson); if(rson) mark_inv(rson); s[x].inv=0; } if(s[x].tag) { if(lson) mark_tag(lson,s[x].tag); if(rson) mark_tag(rson,s[x].tag); s[x].tag=0; } } void rotate(int x) { int old=s[x].f,fold=s[old].f,which=get(x); s[old].ch[which]=s[x].ch[which^1]; if(s[old].ch[which]) s[s[old].ch[which]].f=old; s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold; if(fold) s[fold].ch[s[fold].ch[1]==old]=x; pushup(old),pushup(x); } void splay(int x,int &tar) { int u=s[tar].f,fa; for(;(fa=s[x].f)!=u;rotate(x)) if(s[fa].f!=u) rotate(get(fa)==get(x)?fa:x); tar=x; } int find(int x,int kth) { pushdown(x); if(s[lson].siz>=kth) return find(lson,kth); else if(s[lson].siz+1==kth) return x; else return find(rson,kth-s[lson].siz-1); } int split(int x,int y) { int l=find(root,x); splay(l,root); int r=find(root,y+2); splay(r,s[root].ch[1]); int tmp=s[s[root].ch[1]].ch[0]; return tmp; } void build(int &x,int l,int r,int ff) { x=++tot; s[x].f=ff; int mid=(l+r)>>1; s[x].w=A[mid]; if(l<mid) build(lson,l,mid-1,x); if(r>mid) build(rson,mid+1,r,x); pushup(x); } void setIO(string s) { freopen((s+".in").c_str(),"r",stdin); } int main() { // setIO("input"); int i,j,n,Q; scanf("%d%d%s",&n,&Q,str+1); for(i=2;i<=n+1;++i) A[i]=str[i-1]=='('?-1:1; build(root,1,n+2,0); for(i=1;i<=Q;++i) { char op[10]; scanf("%s",op); int x,y; char z; if(op[0]=='R') { scanf("%d%d%s",&x,&y,op); int p=split(x,y); if(op[0]==')') mark_tag(p,1); else mark_tag(p,-1); while(s[p].f) pushup(s[p].f),p=s[p].f; } if(op[0]=='S') { scanf("%d%d",&x,&y); int p=split(x,y); mark_swa(p); while(s[p].f) pushup(s[p].f),p=s[p].f; } if(op[0]=='I') { scanf("%d%d",&x,&y); int p=split(x,y); mark_inv(p); while(s[p].f) pushup(s[p].f),p=s[p].f; } if(op[0]=='Q') { int x,y; scanf("%d%d",&x,&y); int p=split(x,y); printf("%d\n",(s[p].sum[0][0]+1)/2+(s[p].sum[0][1]+1)/2); } } return 0; }