标签:
神题。
用-1表示左括号,1表示右括号,lmax表示从左开始的最大连续和,rmin表示从右开始的最小连续和,答案为(lmax+1)/2+(-rmin+1)/2。
Splay维护即可。
#include<bits/stdc++.h> #define L(t) (t)->c[0] #define R(t) (t)->c[1] #define Z(t) (L(t)->s+1) #define M (l+r>>1) using namespace std; struct node{ int v,s; int sum,lmin,lmax,rmin,rmax; int same; bool flip,rev; node* c[2]; node(int v,node* a,node* u) :v(v),sum(v){ lmin=lmax=rmin=rmax =s=same=flip=rev=0; c[0]=a,c[1]=u; } }*null=new node(0,0,0),*root; void same(int s,node* t){ t->flip=t->rev=0; t->sum=t->s*(t->v=t->same=s); t->lmin=t->rmin=min(t->sum,0); t->lmax=t->rmax=max(t->sum,0); } void flip(node* t){ if(t->same) return same(t->v*-1,t); t->flip^=1; t->v*=-1,t->sum*=-1; swap(t->lmin*=-1,t->lmax*=-1); swap(t->rmin*=-1,t->rmax*=-1); } void rev(node* t){ if(t->same) return; t->rev^=1; swap(L(t),R(t)); swap(t->lmin,t->rmin); swap(t->lmax,t->rmax); } void devolve(node* t){ if(t==null) return; for(int i=0;i!=2;++i){ if(t->same) same(t->v,t->c[i]); if(t->flip) flip(t->c[i]); if(t->rev) rev(t->c[i]); } t->same=t->flip=t->rev=0; } node* update(node* t){ devolve(L(t)); devolve(R(t)); t->s=R(t)->s+Z(t); t->sum=L(t)->sum+t->v+R(t)->sum; t->lmin=min(L(t)->lmin, L(t)->sum+t->v+R(t)->lmin); t->lmax=max(L(t)->lmax, L(t)->sum+t->v+R(t)->lmax); t->rmin=min(R(t)->rmin, R(t)->sum+t->v+L(t)->rmin); t->rmax=max(R(t)->rmax, R(t)->sum+t->v+L(t)->rmax); return t; } void link(bool i,node*& t,node*& s){ node* d=t->c[i]; t->c[i]=s; s=update(t); t=d; } void splay(int v,node*& t=root){ node* d[]={null,null}; while(1){ devolve(t); if(v==Z(t)) break; bool i=v>Z(t); v-=i*Z(t); devolve(t->c[i]); if(v!=Z(t->c[i]) &&i==v>Z(t->c[i])){ v-=i*Z(t->c[i]); link(i,t,t->c[i]->c[i^1]); } link(i,t,d[i]); } for(int i=0;i!=2;++i){ node* s=t->c[i^1]; while(d[i]!=null) link(i,d[i],s); t->c[i^1]=s; } update(t); } node* build(char* v,int l,int r){ return l>r?null :update(new node( v[M]^‘(‘?1:-1, build(v,l,M-1), build(v,M+1,r))); } node*& interval(int l,int r){ splay(l); splay(r-l+2,R(root)); return L(R(root)); } char s[100010]; int main(){ int n,m,u,v; scanf("%d%d%s",&n,&m,s+1); root=build(s,0,n+1); while(m--){ char t[8],a[2]; scanf("%s%d%d",t,&u,&v); if(*t==‘R‘){ scanf("%s",a); same(*a^‘(‘?1:-1, interval(u,v)); } if(*t==‘S‘) rev(interval(u,v)); if(*t==‘I‘) flip(interval(u,v)); if(*t==‘Q‘){ node* t=interval(u,v); printf("%d\n",(t->lmax +1)/2+(-t->rmin+1)/2); } } }
bzoj2329: [HNOI2011]括号修复 Splay
标签:
原文地址:http://www.cnblogs.com/f321dd/p/5496015.html