您的位置:首页 > 其它

【bzoj2329】[HNOI2011]括号修复 splay

2015-12-29 14:35 393 查看
先考虑一下,给定一个括号序列,怎样求答案。

括号序列化简后一定是这个样子的,)))))(((

这样子的答案就是(左括号数+1)/2+(右括号数+1)/2

那么,我们只需要维护好从左边有多少个右括号和从右边有多少个左括号就可以求答案了。

记(为-1,)为1,这样()相加后就被抵消了。

于是,我们只需要维护一个类似最大连续子段和中的从左边延伸多少就可以了。

操作其实都非常基础。

覆盖标记时,记得把其他标记全部清零。

反转标记时,记得吧覆盖标记反转。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 100010

using namespace std;

int ch[maxn][2],fa[maxn],lmax[maxn],rmax[maxn],lmin[maxn],rmin[maxn],w[maxn],sum[maxn],size[maxn];
bool tag[maxn],rev[maxn];
int flag[maxn],a[maxn];
char s[maxn];
int n,m,tot,T,root;

int dir(int x)
{
	return x==ch[fa[x]][1];
}

void update(int x)
{
	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+w[x];
	lmax[x]=max(lmax[ch[x][0]],sum[ch[x][0]]+w[x]+lmax[ch[x][1]]);
	rmax[x]=max(rmax[ch[x][1]],sum[ch[x][1]]+w[x]+rmax[ch[x][0]]);
	lmin[x]=min(lmin[ch[x][0]],sum[ch[x][0]]+w[x]+lmin[ch[x][1]]);
	rmin[x]=min(rmin[ch[x][1]],sum[ch[x][1]]+w[x]+rmin[ch[x][0]]);
}

void invert(int x)
{
	lmin[x]=-lmin[x];lmax[x]=-lmax[x];
	rmin[x]=-rmin[x];rmax[x]=-rmax[x];
	swap(lmax[x],lmin[x]);swap(rmax[x],rmin[x]);
	w[x]=-w[x];sum[x]=-sum[x];
	if (flag[x]) flag[x]=-flag[x]; else tag[x]^=1;
}

void reverse(int x)
{
	swap(lmax[x],rmax[x]);swap(lmin[x],rmin[x]);
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}

void replace(int x,int f)
{
	w[x]=f;sum[x]=size[x]*f;
	if (f==1) lmax[x]=rmax[x]=sum[x],lmin[x]=rmin[x]=0;
	if (f==-1) lmin[x]=rmin[x]=sum[x],lmax[x]=rmax[x]=0;
	tag[x]=0;rev[x]=0;flag[x]=f;
}

void push_down(int x)
{
	if (tag[x])
	{
		if (ch[x][0]) invert(ch[x][0]);
		if (ch[x][1]) invert(ch[x][1]);
		tag[x]=0;
	}
	if (rev[x])
	{
		if (ch[x][0]) reverse(ch[x][0]);
		if (ch[x][1]) reverse(ch[x][1]);
		rev[x]=0;
	}
	if (flag[x])
	{
		if (ch[x][0]) replace(ch[x][0],flag[x]);
		if (ch[x][1]) replace(ch[x][1],flag[x]);
		flag[x]=0;
	}
}

void down(int x)
{
	if (fa[x]) down(fa[x]);
	push_down(x);
}

void rotate(int x)
{
	int y,z,a,b,c;
	y=fa[x];z=fa[y];b=dir(x);a=ch[x][!b];
	if (z==0) root=x;
	else
	{
		c=dir(y);ch[z][c]=x;
	}
	fa[x]=z;fa[y]=x;ch[x][!b]=y;ch[y][b]=a;
	if (a) fa[a]=y;
	update(y);update(x);
}

void splay(int x,int i)
{
	down(x);
	int y,z,b,c;
	while (fa[x]!=i)
	{
		y=fa[x];z=fa[y];
		if (z==i) rotate(x);
		else
		{
			b=dir(x);c=dir(y);
			if (b^c)
			{
				rotate(x);rotate(x);
			}
			else
			{
				rotate(y);rotate(x);
			}
		}
	}
}

int find_k(int x,int k)
{
	push_down(x);
	if (size[ch[x][0]]==k-1) return x;
	if (size[ch[x][0]]>k-1) return find_k(ch[x][0],k);
	else return find_k(ch[x][1],k-size[ch[x][0]]-1);
}

void build_tree(int l,int r,int tt)
{
	int mid=(l+r)/2;
	w[tt]=a[mid];
	if (l==r) {size[tt]=1;sum[tt]=w[tt];if (w[tt]>0) lmax[tt]=rmax[tt]=1; else lmin[tt]=rmin[tt]=-1;return;}
	if (l<mid) {tot++;ch[tt][0]=tot;fa[tot]=tt;build_tree(l,mid-1,tot);}
	if (mid<r) {tot++;ch[tt][1]=tot;fa[tot]=tt;build_tree(mid+1,r,tot);}
	update(tt);
}

int query(int l,int r)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],r-l+2);splay(y,x);
	return (lmax[ch[y][0]]+1)/2+(-rmin[ch[y][0]]+1)/2;
}

void Reverse(int l,int r)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],r-l+2);splay(y,x);
	reverse(ch[y][0]);
}

void Replace(int l,int r,int d)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],r-l+2);splay(y,x);
	replace(ch[y][0],d);
}

void Invert(int l,int r)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],r-l+2);splay(y,x);
	invert(ch[y][0]);
}

int main()
{
	scanf("%d%d",&n,&T);
	scanf("%s",s+1);
	for (int i=1;i<=n;i++) if (s[i]=='(') a[i]=-1; else a[i]=1;
	tot=2;root=1;
	fa[1]=0;size[1]=2;ch[1][1]=2;
	fa[2]=1;size[2]=1;
	tot++;ch[2][0]=tot;fa[tot]=2;
	build_tree(1,n,tot);
	update(2);update(1);
	while (T--)
	{
		int x,y;
		scanf("%s%d%d",s,&x,&y);
		if (s[0]=='Q') printf("%d\n",query(x,y));
		if (s[0]=='S') Reverse(x,y);
		if (s[0]=='R')
		{
			int w;
			scanf("%s",s);
			if (s[0]=='(') w=-1; else w=1;
			Replace(x,y,w);
		}
		if (s[0]=='I') Invert(x,y);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: