bzoj2329[HNOI2011]括号修复 Splay

Posted GXZlegend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2329[HNOI2011]括号修复 Splay相关的知识,希望对你有一定的参考价值。

题目描述

技术分享图片


题解

Splay

由于有区间反转操作,因此考虑Splay。

考虑答案:缩完括号序列后剩下的一定是 $a$ 个‘)‘+ $b$ 个‘(‘,容易发现答案等于 $\lceil\frac a2\rceil+\lceil\frac b2\rceil$ 。

怎么维护:区间合并,对于每个节点维护子树缩完括号序列后‘)‘和‘(‘的数目,然后pushup时考虑缩括号序列的过程,相应调整即可。

由于有Invent操作,因此还需要维护反括号序列缩完之后‘)‘和‘(‘的数目,并维护相应标记。

由于有Swap操作,因此需要维护相应标记。需要注意的是:这里的Swap不是镜面反转,而是直接交换,换句话说就是翻转后括号方向不变。因此不能直接交换‘)‘的数目和‘(‘的数目,而是相当于交换后再Invent一次,即交换‘)‘的数目和反括号序列‘(‘的数目、交换‘(‘的数目和反括号序列‘)‘的数目。

由于有Replace操作,因此还需要维护区间染色标记。

时间复杂度 $O(n\log n)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
int fa[N] , c[2][N] , si[N] , w[N] , sum[N][2][2] , tag[N] , rev[N] , flip[N] , root;
char str[N];
inline void pushup(int x)
{
	int l = c[0][x] , r = c[1][x];
	si[x] = si[l] + si[r] + 1;
	sum[x][0][0] = sum[l][0][0] + max(sum[r][0][0] - sum[l][0][1] + w[x] , 0);
	sum[x][0][1] = sum[r][0][1] + max(sum[l][0][1] - sum[r][0][0] - w[x] , 0);
	sum[x][1][0] = sum[l][1][0] + max(sum[r][1][0] - sum[l][1][1] - w[x] , 0);
	sum[x][1][1] = sum[r][1][1] + max(sum[l][1][1] - sum[r][1][0] + w[x] , 0);
}
inline void pushdown(int x)
{
	int l = c[0][x] , r = c[1][x];
	if(rev[x])
	{
		w[l] = -w[l] , tag[l] = -tag[l] , swap(sum[l][0][0] , sum[l][1][0]) , swap(sum[l][0][1] , sum[l][1][1]) , rev[l] ^= 1;
		w[r] = -w[r] , tag[r] = -tag[r] , swap(sum[r][0][0] , sum[r][1][0]) , swap(sum[r][0][1] , sum[r][1][1]) , rev[r] ^= 1;
		rev[x] = 0;
	}
	if(flip[x])
	{
		swap(c[0][l] , c[1][l]) , swap(sum[l][0][0] , sum[l][1][1]) , swap(sum[l][0][1] , sum[l][1][0]) , flip[l] ^= 1;
		swap(c[0][r] , c[1][r]) , swap(sum[r][0][0] , sum[r][1][1]) , swap(sum[r][0][1] , sum[r][1][0]) , flip[r] ^= 1;
		flip[x] = 0;
	}
	if(tag[x])
	{
		w[l] = w[r] = tag[l] = tag[r] = tag[x];
		if(tag[x] == 1)
		{
			sum[l][0][0] = sum[l][1][1] = si[l] , sum[l][0][1] = sum[l][1][0] = 0;
			sum[r][0][0] = sum[r][1][1] = si[r] , sum[r][0][1] = sum[r][1][0] = 0;
		}
		else
		{
			sum[l][0][0] = sum[l][1][1] = 0 , sum[l][0][1] = sum[l][1][0] = si[l];
			sum[r][0][0] = sum[r][1][1] = 0 , sum[r][0][1] = sum[r][1][0] = si[r];
		}
		tag[x] = 0;
	}
}
int build(int l , int r)
{
	if(l > r) return 0;
	int mid = (l + r) >> 1;
	c[0][mid] = build(l , mid - 1) , fa[c[0][mid]] = mid;
	c[1][mid] = build(mid + 1 , r) , fa[c[1][mid]] = mid;
	pushup(mid);
	return mid;
}
inline void rotate(int &k , int x)
{
	int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;
	if(y == k) k = x;
	else c[c[1][z] == y][z] = x;
	fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
	pushup(y) , pushup(x);
}
inline void splay(int &k , int x)
{
	while(x != k)
	{
		int y = fa[x] , z = fa[y];
		if(y != k)
		{
			if((c[0][y] == x) ^ (c[0][z] == y)) rotate(k , x);
			else rotate(k , y);
		}
		rotate(k , x);
	}
}
int find(int k , int x)
{
	pushdown(k);
	if(x <= si[c[0][k]]) return find(c[0][k] , x);
	else if(x > si[c[0][k]] + 1) return find(c[1][k] , x - si[c[0][k]] - 1);
	else return k;
}
int split(int l , int r)
{
	int a = find(root , l) , b = find(root , r + 2);
	splay(root , a) , splay(c[1][root] , b);
	return c[0][c[1][root]];
}
int main()
{
	int n , m , i , x , y , z;
	scanf("%d%d%s" , &n , &m , str + 2);
	for(i = 2 ; i <= n + 1 ; i ++ ) w[i] = (str[i] == ‘)‘ ? 1 : -1);
	root = build(1 , n + 2);
	while(m -- )
	{
		scanf("%s%d%d" , str , &x , &y) , z = split(x , y);
		if(str[0] == ‘R‘)
		{
			scanf("%s" , str);
			if(str[0] == ‘)‘) sum[z][0][0] = sum[z][1][1] = si[z] , sum[z][0][1] = sum[z][1][0] = 0 , w[z] = tag[z] = 1;
			else sum[z][0][0] = sum[z][1][1] = 0 , sum[z][0][1] = sum[z][1][0] = si[z] , w[z] = tag[z] = -1;
			pushup(fa[z]) , pushup(root);
		}
		else if(str[0] == ‘S‘) swap(c[0][z] , c[1][z]) , swap(sum[z][0][0] , sum[z][1][1]) , swap(sum[z][0][1] , sum[z][1][0]) , flip[z] ^= 1 , pushup(fa[z]) , pushup(root);
		else if(str[0] == ‘I‘) w[z] = -w[z] , tag[z] = -tag[z] , swap(sum[z][0][0] , sum[z][1][0]) , swap(sum[z][0][1] , sum[z][1][1]) , rev[z] ^= 1 , pushup(fa[z]) , pushup(root);
		else printf("%d\n" , (sum[z][0][0] + 1) / 2 + (sum[z][0][1] + 1) / 2);
	}
	return 0;
}

 

以上是关于bzoj2329[HNOI2011]括号修复 Splay的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2329/2209[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay

BZOJ2329 HNOI2011 括号修复 平衡树

bzoj2329[HNOI2011]括号修复 Splay

bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)

bzoj2329: [HNOI2011]括号修复

[HNOI2011][bzoj 2329] 括号修复 [splay+前缀和]