BZOJ2329 HNOI2011 括号修复 平衡树
Posted WDZRMPCBIT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2329 HNOI2011 括号修复 平衡树相关的知识,希望对你有一定的参考价值。
题意:给定一个由(,)组成的括号序列,维护:1、将[a,b]修改为同一种半括号 2、将[a,b]翻转 3、将[a,b]的(变为),)变为( 4、求[a,b]最少要添加多少个括号才能合法
题解:
不算太裸的平衡树……论标记的正确打法。
对于一个括号序列,我们总能简化成一个左边全是右括号,右边全是左括号的序列,像酱紫:)))))(((((。当然有可能是没有左括号或者右括号的
我们定义)==-1,(==1。然后我们用打标记的方法来维护从左起的最小序列和lmin和从右起的最大序列和rmax,显然这两个的值分别是简化后右括号和左括号的数量,那么答案就是(-lmin+1)/2+(rmax+1)/2
我们建树来维护lmin,lmax,rmin,rmax,翻转、改变、取反操作全部用打标记的方法,至于怎么打可以参考线段树的lazy标记,其中取反操作就是交换min和max。
有一个细节上的问题:如果改变操作在取反操作之后进行,就要删除取反标记,因为之前不论你怎么取反,一改变就统统作废了。下方标记时亦是如此。
最后就是代码实现了……
#include <cstdio> #include <climits> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=100000+2; typedef struct NODE{ int c,s,v,lmin,rmin,lmax,rmax; bool same,rev,inv; NODE *child[2],*f; NODE(int _v,NODE *_f):s(_v),v(_v),f(_f){} } *TREE; TREE root,Null; int N,M,a[MAXN]; char s[MAXN]; TREE NewNode(int v,TREE f){ TREE x=new NODE(v,f); x->c=1; x->lmax=x->rmax=max(v,0); x->lmin=x->rmin=min(v,0); x->same=x->rev=x->inv=0; x->child[0]=x->child[1]=Null; return x; } void Initialization(){ Null=NewNode(0,0),Null->c=0; root=NewNode(0,Null); root->child[1]=NewNode(0,root); Null->s=root->s=root->child[1]->s=0; } void Pushup(TREE x){ if(x==Null) return; x->c=x->child[0]->c+x->child[1]->c+1; x->s=x->child[0]->s+x->child[1]->s+x->v; x->lmin=min(x->child[0]->lmin,x->child[0]->s+x->v+min(0,x->child[1]->lmin)); x->rmin=min(x->child[1]->rmin,x->child[1]->s+x->v+min(0,x->child[0]->rmin)); x->lmax=max(x->child[0]->lmax,x->child[0]->s+x->v+max(0,x->child[1]->lmax)); x->rmax=max(x->child[1]->rmax,x->child[1]->s+x->v+max(0,x->child[0]->rmax)); } void Pushdown(TREE x){ if(x==Null) return; if(x->rev){ swap(x->child[0],x->child[1]),swap(x->lmin,x->rmin),swap(x->lmax,x->rmax); x->child[0]->rev^=1,x->child[1]->rev^=1,x->rev=0; } if(x->same){ x->s=x->v*x->c; x->lmax=x->rmax=max(0,max(x->v,x->s)); x->lmin=x->rmin=min(0,min(x->v,x->s)); x->child[0]->same=1,x->child[0]->v=x->v,x->child[0]->inv=0;//删除取反标记 x->child[1]->same=1,x->child[1]->v=x->v,x->child[1]->inv=0;//删除取反标记 x->same=0; } if(x->inv){ x->v=-x->v,x->s=-x->s; swap(x->lmin,x->lmax),swap(x->rmin,x->rmax); x->lmin*=-1,x->rmin*=-1,x->lmax*=-1,x->rmax*=-1; x->child[0]->inv^=1,x->child[1]->inv^=1,x->inv=0; } } void Rotate(TREE x,bool t){ TREE y=x->f; Pushdown(x->child[0]),Pushdown(x->child[1]),Pushdown(y->child[t]); y->child[!t]=x->child[t],x->child[t]->f=y,x->f=y->f; if(y->f->child[0]==y) y->f->child[0]=x; else y->f->child[1]=x; y->f=x,x->child[t]=y; Pushup(y),Pushup(x); if(y==root) root=x; } void Splay(TREE x,TREE y){ Pushdown(x); while(x->f!=y) if(x->f->f==y) if(x->f->child[0]==x) Rotate(x,1); else Rotate(x,0); else if(x->f->f->child[0]==x->f) if(x->f->child[0]==x) Rotate(x->f,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1); else if(x->f->child[0]==x) Rotate(x,1),Rotate(x,0); else Rotate(x->f,0),Rotate(x,0); } void Select(int p,TREE y){ TREE x=root;Pushdown(x); while(p!=x->child[0]->c+1){ if(p<=x->child[0]->c) x=x->child[0]; else p-=x->child[0]->c+1,x=x->child[1]; Pushdown(x); } Splay(x,y); } void Insert(int p,int n,int *a){ TREE s,t; s=t=NewNode(a[1],Null); for(int i=2;i<=n;i++) t=t->child[1]=NewNode(a[i],t); Select(p+1,Null),Select(p+2,root); root->child[1]->child[0]=s,s->f=root->child[1]; Splay(t,Null); } void Change(int p,int n,int v){ Select(p,Null),Select(p+n+1,root); root->child[1]->child[0]->same=1,root->child[1]->child[0]->v=v; root->child[1]->child[0]->inv=0;//删除取反标记 Splay(root->child[1]->child[0],Null); } void Reverse(int p,int n){ Select(p,Null),Select(p+n+1,root); root->child[1]->child[0]->rev^=1; Splay(root->child[1]->child[0],Null); } void Invert(int p,int n){ Select(p,Null),Select(p+n+1,root); root->child[1]->child[0]->inv^=1; Splay(root->child[1]->child[0],Null); } int Query(int p,int n){ Select(p,Null),Select(p+n+1,root); Pushdown(root->child[1]->child[0]); int x=(-root->child[1]->child[0]->lmin+1)>>1; int y=(root->child[1]->child[0]->rmax+1)>>1; return x+y; } int main(){ Initialization(); cin >> N >> M; cin >> s; for(int i=1;i<=N;i++) if(s[i-1]==\'(\') a[i]=1; else a[i]=-1; Insert(0,N,a); for(int i=1,a,b;i<=M;i++){ cin >> s; cin >> a >> b; if(strstr(s,"Replace")){ cin >> s; if(s[0]==\'(\') Change(a,b-a+1,1); else Change(a,b-a+1,-1); } if(strstr(s,"Swap")) Reverse(a,b-a+1); if(strstr(s,"Invert")) Invert(a,b-a+1); if(strstr(s,"Query")) cout << Query(a,b-a+1) << endl; } return 0; }
以上是关于BZOJ2329 HNOI2011 括号修复 平衡树的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2329/2209[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)