码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2329: [HNOI2011]括号修复 Splay

时间:2016-05-15 21:37:16      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:

神题。

用-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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!