bzoj 2209: [Jsoi2011]括号序列(splay)

2209: [Jsoi2011]括号序列

Time Limit: 20 Sec   Memory Limit: 259 MB
Submit: 1082   Solved: 526
[ Submit][ Status][ Discuss]

Description

Input

输入数据的第一行包含两个整数N和Q,分别表示括号序列的长度,以及操作的个数。 第二行包含一个长度为N的括号序列。 接下来Q行,每行三个整数t、x和y,分别表示操作的类型、操作的开始位置和操作的结 束位置,输入数据保证x不小于y。其中t=0表示询问操作、t=1表示反转操作、t=2表示翻转操 作。

Output

对于每一个询问操作,输出一行,表示将括号序列的该子序列修改为配对,所需的最少改动 个数。

Sample Input

6 3
)(())(
0 1 6
0 1 4
0 3 4

Sample Output

2
2
0

HINT

100%的数据满足N,Q不超过10^5

Source

第一轮

[ Submit][ Status][ Discuss]


题解:splay 

我们将括号序列改成-1与1的序列,用-1表示(,用1表示)。

那么一段区间中前缀和的最大值就是未匹配的)的数量(prex表示),后缀和的最小值为未匹配的(的数量(sufn表示)。

如果未匹配的(,)都是偶数的话,那答案就是(prex+sufn)/2

如果未匹配的(,)都是奇数的话,那答案就是(prex+sufn)/2+1 (至于为什么,画一画括号找找规律啦)

翻转操作: 交换左右子树,打翻转标记,直接交换pre 和 suf 数组即可,因为以前的前缀变成了后缀,数值并未发生改变。

反转操作:打反转标记,将pren,prex,sufn,sufx,sum,key取反,swap(pren,prex),swap(sufn,sufx)。因为反转之后-1,与1,都会发生变化,而且取反后最大值与最小值都会发生大小交换。

有两个标记会不会发生标记冲突呢?这道题比较好,通过手动操作可以发现两个标记互不影响,先下放哪一个的效果都是相同的。

#include
#include
#include
#include
#include
#define N 500003
using namespace std;
int n,m,fa[N],size[N],sum[N],key[N],ch[N][3],prefx[N],prefn[N],sufx[N],sufn[N];
int pos[N],root,neg[N],rev[N],cnt;
char s[N];
void update(int now)//前缀和的最大值是多出的)的数量(最大值应该大于等于0),后缀和的最小值是多出的( 的数量(最小值应该小于等于0) 
{
	prefx[0]=sufx[0]=-1000000000; 
	prefn[0]=sufn[0]=1000000000; key[0]=0;
	int l=ch[now][0]; int r=ch[now][1];
	size[now]=size[l]+size[r]+1;
	sum[now]=sum[l]+sum[r]+key[now];
	int lenp=max(sum[l]+key[now],sum[l]+prefx[r]+key[now]);
	prefx[now]=max(lenp,prefx[l]);
	lenp=min(sum[l]+key[now],sum[l]+prefn[r]+key[now]);
	prefn[now]=min(lenp,prefn[l]);
	int lens=max(sum[r]+key[now],sum[r]+sufx[l]+key[now]);
	sufx[now]=max(lens,sufx[r]);
	lens=min(sum[r]+key[now],sum[r]+sufn[l]+key[now]);
	sufn[now]=min(lens,sufn[r]);
}
void change(int now)
{
	swap(prefx[now],sufx[now]);
	swap(prefn[now],sufn[now]);
}
void change1(int now)
{
	sum[now]=-sum[now]; key[now]=-key[now];
	prefx[now]=-prefx[now]; sufx[now]=-sufx[now];
	prefn[now]=-prefn[now]; sufn[now]=-sufn[now];
	swap(prefx[now],prefn[now]);
	swap(sufn[now],sufx[now]);
}
void pushdown(int x)
{
	if (rev[x])
	 {
	 	change(ch[x][0]); change(ch[x][1]);
	 	swap(ch[x][0],ch[x][1]);
	 	rev[ch[x][0]]^=1; rev[ch[x][1]]^=1;
	 	rev[x]=0;
	 }
	if (neg[x])
	 {
	 	change1(ch[x][0]); change1(ch[x][1]);
	 	neg[ch[x][0]]^=1; neg[ch[x][1]]^=1;
	 	neg[x]=0;
	 }
}
int build(int l,int r,int f)
{
	if (l>r) return 0;
	int mid=(l+r)/2; int now=++cnt;
	key[now]=pos[mid];  fa[now]=f;
	ch[now][0]=build(l,mid-1,now);
	ch[now][1]=build(mid+1,r,now);
	update(now);
	//cout<0) ans1=0;
			else ans1=-ans1;
			if (ans<0) ans=0;
	 	 	if (ans%2||ans1%2)  printf("%d\n",(ans+ans1)/2+1);
	 	 	else printf("%d\n",(ans+ans1)/2);
		 }
		if (opt==1)
		 {
		 	neg[t]^=1;
		 	change1(t); update(ch[root][1]); update(root);
		 }
		if (opt==2)
		 {
		    rev[t]^=1;
			change(t);	update(ch[root][1]); update(root);
		 }
	 }
}


你可能感兴趣的:(平衡树)