[BZOJ2329][HNOI2011]括号修复

bzoj
luogu

题意

你需要维护一个括号序列,支持如下四种操作:
1、把区间\([l,r]\)全部改成(或是)
2、把区间\([l,r]\)翻转。
3、把区间\([l.r]\)反转,即())(
4、查询区间\([l,r]\)至少要修改几个括号才能全部匹配。

sol

一个区间的括号去掉匹配后一定长成)))))((((((这个样子。
所以答案就是未匹配左括号个数/2+未匹配右括号个数/2,除法向上取整。
考虑把左括号看成1,右括号看成-1。这样左边的未匹配右括号个数就是最小前缀和的绝对值,右边的就是最大后缀和。
要维护区间翻转反转就还得同时维护最大前缀和与最小后缀和。
注意这里最小XX数的上界是\(0\),最大XX数的下界也是\(0\)
\(splay\)维护即可。

区间覆盖的优先级高于翻转反转,所以区间覆盖后要把翻转反转的标记都清掉。翻转反转的优先级相同,先翻转再反转和先反转再翻转是一样的。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 1e5+5;
int n,m,val[N],fa[N],ch[2][N],lmi[N],rmi[N],lmx[N],rmx[N],sum[N],sz[N],root;
int tag[N],inv[N],rev[N];
char s[N];
void pushup(int x)
{
	sum[x]=sum[ch[0][x]]+val[x]+sum[ch[1][x]];
	sz[x]=sz[ch[0][x]]+sz[ch[1][x]]+1;
	lmi[x]=min(lmi[ch[0][x]],sum[ch[0][x]]+val[x]+lmi[ch[1][x]]);
	rmi[x]=min(rmi[ch[1][x]],sum[ch[1][x]]+val[x]+rmi[ch[0][x]]);
	lmx[x]=max(lmx[ch[0][x]],sum[ch[0][x]]+val[x]+lmx[ch[1][x]]);
	rmx[x]=max(rmx[ch[1][x]],sum[ch[1][x]]+val[x]+rmx[ch[0][x]]);
}
void cover(int x,int v)
{
	if (!x) return;
	sum[x]=sz[x]*v;
	lmi[x]=rmi[x]=min(0,sum[x]);
	lmx[x]=rmx[x]=max(0,sum[x]);
	val[x]=tag[x]=v;inv[x]=rev[x]=0;
}
void reverse(int x)
{
	if (!x) return;
	swap(ch[0][x],ch[1][x]);
	swap(lmi[x],rmi[x]);swap(lmx[x],rmx[x]);
	rev[x]^=1;
}
void inverse(int x)
{
	if (!x) return;
	swap(lmi[x],lmx[x]);lmi[x]*=-1;lmx[x]*=-1;
	swap(rmi[x],rmx[x]);rmi[x]*=-1;rmx[x]*=-1;
	val[x]*=-1;sum[x]*=-1;inv[x]^=1;
}
void pushdown(int x)
{
	if (tag[x]) cover(ch[0][x],tag[x]),cover(ch[1][x],tag[x]),tag[x]=0;
	if (rev[x]) reverse(ch[0][x]),reverse(ch[1][x]),rev[x]=0;
	if (inv[x]) inverse(ch[0][x]),inverse(ch[1][x]),inv[x]=0;
}
int build(int l,int r,int ff)
{
	if (l>r) return 0;
	int mid=l+r>>1;
	fa[mid]=ff;
	ch[0][mid]=build(l,mid-1,mid);
	ch[1][mid]=build(mid+1,r,mid);
	pushup(mid);return mid;
}
bool son(int x){return x==ch[1][fa[x]];}
void rotate(int x)
{
	int y=fa[x],z=fa[y],c=son(x);
	ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y;
	fa[x]=z;if (z) ch[son(y)][z]=x;
	ch[c^1][x]=y;fa[y]=x;pushup(y);
}
void splay(int x,int goal)
{
	for (int y=fa[x];y!=goal;rotate(x),y=fa[x])
		if (fa[y]!=goal) son(x)^son(y)?rotate(x):rotate(y);
	pushup(x);if (!goal) root=x;
}
void Kth(int k,int goal)
{
	int x=root;
	while (233)
	{
		pushdown(x);
		if (k<=sz[ch[0][x]]) x=ch[0][x];
		else if (k==sz[ch[0][x]]+1) {splay(x,goal);return;}
		else k-=sz[ch[0][x]]+1,x=ch[1][x];
	}
}
int main()
{
	n=gi();m=gi();scanf("%s",s+2);
	for (int i=2;i<=n+1;++i) val[i]=s[i]=='('?1:-1;
	root=build(1,n+2,0);
	while (m--)
	{
		scanf("%s",s);int l=gi(),r=gi();char op;
		Kth(l,0);Kth(r+2,root);int pos=ch[0][ch[1][root]];
		if (s[0]=='R') op=getchar(),cover(pos,op=='('?1:-1);
		if (s[0]=='S') reverse(pos);
		if (s[0]=='I') inverse(pos);
		if (s[0]=='Q') printf("%d\n",(-lmi[pos]+1)/2+(rmx[pos]+1)/2);
	}
	return 0;
}
posted @ 2018-04-12 17:00  租酥雨  阅读(258)  评论(0编辑  收藏  举报