BZOJ 2329 HNOI 2011 括号修复 Splay维护最大连续子段和

题目大意:给出一个括号序列,问一段区间最少需要修改多少括号使得这一段括号变成一段完整的括号序列。

思路:题解见http://ydcydcy1.blog.163.com/blog/static/2160890402013116111134791/ OTZ ydc

维护起来稍微有些麻烦啊。。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
using namespace std;
#define WORKPATH (root->son[1]->son[0])

struct SplayTree *_nil;

struct SplayTree{
	int val,size;
	SplayTree *son[2],*father;

	int sum,l_min,l_max,r_min,r_max;
	bool reverse,invert;
	int change;

	bool Check() {
		return father->son[1] == this;
	}
	void Combine(SplayTree *a,bool dir) {
		son[dir] = a;
		a->father = this;
	}
	void Reverse() {
		if(this == _nil)	return ;
		reverse ^= 1;
		swap(l_min,r_min);
		swap(l_max,r_max);
		swap(son[0],son[1]);
	}
	void Invert() {
		if(this == _nil)	return ;
		invert ^= 1;
		l_min *= -1,l_max *= -1;
		r_min *= -1,r_max *= -1;
		sum *= -1,val *= -1;
		swap(l_min,l_max);
		swap(r_min,r_max);
	}
	void Change(int _) {
		if(this == _nil)	return ;
		change = val = _;
		sum = _ * size;
		l_min = r_min = min(0,_ * size);
		l_max = r_max = max(0,_ * size);
		reverse = invert = false;
	}
	void PushUp() {
		if(this == _nil)
			return ;
		size = son[0]->size + son[1]->size + 1;
		sum = son[0]->sum + son[1]->sum + val;
		l_min = min(son[0]->l_min,son[0]->sum + val + son[1]->l_min);
		l_max = max(son[0]->l_max,son[0]->sum + val + son[1]->l_max);
		r_min = min(son[1]->r_min,son[1]->sum + val + son[0]->r_min);
		r_max = max(son[1]->r_max,son[1]->sum + val + son[0]->r_max);
	}
	void PushDown() {
		if(this == _nil)	return ;
		if(change) {
			son[0]->Change(change);
			son[1]->Change(change);
			change = 0;
		}
		if(invert) {
			son[0]->Invert();
			son[1]->Invert();
			invert = false;
		}
		if(reverse) {
			son[0]->Reverse();
			son[1]->Reverse();
			reverse = false;
		}
	}
}none,*nil = &none,*root;

char src[MAX];
int length,asks;

void Pretreatment()
{
	nil->son[0] = nil->son[1] = nil->father = nil;
	nil->sum = nil->val = nil->change = nil->size = 0;
	nil->reverse = nil->invert = false;
	_nil = nil;
}

inline SplayTree *NewSplay(int _)
{
	SplayTree *re = new SplayTree();
	re->val = re->sum = _;
	re->size = 1;
	re->l_min = re->r_min = min(_,0);
	re->l_max = re->r_max = max(_,0);
	re->son[0] = re->son[1] = re->father = nil;
	re->reverse = re->invert = false;
	re->change = 0;
	return re;
}

inline void Rotate(SplayTree *a,bool dir)
{
	SplayTree *f = a->father;
	f->PushDown(),a->PushDown();
	f->son[!dir] = a->son[dir];
	f->son[!dir]->father = f;
	a->son[dir] = f;
	a->father = f->father;
	f->father->son[f->Check()] = a;
	f->father = a;
	f->PushUp();
	if(root == f)	root = a;
}

SplayTree *BuildTree(int l,int r)
{
	if(l > r)	return nil;
	int mid = (l + r) >> 1;
	SplayTree *re = NewSplay(src[mid] == '(' ? -1:1);
	re->Combine(BuildTree(l,mid - 1),false);
	re->Combine(BuildTree(mid + 1,r),true);
	re->PushUp();
	return re;
}

inline void Splay(SplayTree *a,SplayTree *aim)
{
	while(a->father != aim) {
		if(a->father->father == aim)
			Rotate(a,!a->Check());
		else if(!a->father->Check()) {
			if(!a->Check())
				Rotate(a->father,true),Rotate(a,true);
			else	Rotate(a,false),Rotate(a,true);
		}
		else {
			if(a->Check())
				Rotate(a->father,false),Rotate(a,false);
			else	Rotate(a,true),Rotate(a,false);
		}
	}
	a->PushUp();
}

SplayTree *Find(SplayTree *a,int k)
{
	a->PushDown();
	if(a->son[0]->size >= k)	return Find(a->son[0],k);
	k -= a->son[0]->size;
	if(k == 1)	return a;
	return Find(a->son[1],k - 1);
}

inline void SplaySeg(int x,int y)
{
	x++,y++;
	Splay(Find(root,x - 1),nil);
	Splay(Find(root,y + 1),root);
}

char s[10];

int main()
{
	Pretreatment();
	cin >> length >> asks;
	scanf("%s",src + 1);
	root = BuildTree(0,length + 1);
	root->father = nil;
	for(int x,y,i = 1; i <= asks; ++i) {
		scanf("%s%d%d",s,&x,&y);
		SplaySeg(x,y);
		if(s[0] == 'R') {
			scanf("%s",s);
			WORKPATH->Change(s[0] == '(' ? -1:1);
		}
		else if(s[0] == 'Q')	printf("%d\n",((WORKPATH->l_max + 1) >> 1) + ((-WORKPATH->r_min + 1) >> 1));
		else if(s[0] == 'S')	WORKPATH->Reverse();
		else if(s[0] == 'I')	WORKPATH->Invert();
	}
	return 0;
}
时间: 2024-08-03 15:16:48

BZOJ 2329 HNOI 2011 括号修复 Splay维护最大连续子段和的相关文章

BZOJ 2329: [HNOI2011]括号修复( splay )

把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, 只是我傻X -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstrin

bzoj2329: [HNOI2011]括号修复 Splay

神题. 用-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

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

题面: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 思路: 显然,操作4中输出补全的最小费用是关键 这决定了我们不可能在splay上只维护1-2个值. 考虑一段括号序列,将其中所有合法序列删去以后,留下的一定是形如 ))))))((( 的序列 因此首先考虑将每段区间左侧不匹配的括号数和右侧不匹配的括号数记录下来,分别为 left[l,r] 和 right[l,r] 此时除了Invert操作以外已经可以满足 但是对于Invert操作,对

BZOJ 2329: [HNOI2011]括号修复 [splay 括号]

题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘('和‘)'组成的字符串,位置标号从 1 到 N.对这个字符串有下列四种操作: Replace a b c:将[a,b]之间的所有括号改成 c.例如:假设原来的字符串为:))())())(,那么执行操作 Replace 2 7 ( 后原来的字符串变为:)(((((()(. Swap a b:将[a,b]

BZOJ 2300 HAOI 2011 防线修建 动态维护凸包

题目大意:一些成熟分布在第一象限中,现在要建造一个防线来保护他们,但是随着时间的推移,必须要舍弃一些城市,但是不会舍弃首都.问最短的防线需要多长. 思路:在每一个时刻求一个上凸包就是答案了.当然这样做时间复杂度就呵呵了.考虑一下动态维护凸包.因为只有上凸包,所以处理起来会相对方便.我们只需把在凸包中的点按照x坐标排序,然后二分一下把点插入凸包,然后左右用斜率维护一下,这样每次插点的时间复杂度大概是O(logn).但是这样只能插点不能删点,所以离线处理一下,把删点转化为插点,最后倒着输出. (我比

BZOJ 2326 HNOI 2011 数学作业 矩阵乘法

题目大意 求一个这样的数:"12345678910111213--"对m取模的值. 思路 观察这个数字的特点,每次向后面添加一个数.也就是原来的数乘10^k之后在加上一个数.而且处理每个数量级的时候是相似的.所以就可以用矩阵乘法来加速.我构造的矩阵是这样的. [当前数字累加数字1]×???数量级10011001???=[新的数字累加数字+11] CODE #include <cstdio> #include <cstring> #include <iost

[BZOJ 2326][HNOI 2011]数学作业(矩阵快速幂)

蒟蒻线性代数太烂了...这个逼题居然卡了半天才做出来,弱的不行啊... 矩阵快速幂,把n这个len位数拆成len次分段快速幂就可以了. 注意取模的数字m<=1e9,所以矩阵乘法运算时要先对乘数取模,防止中间运算结果太大溢出,坑爹啊 代码: #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #d

BZOJ 2338 HNOI 2011 数矩形 计算几何

题目大意:给出平面上的一些点,求这些点中组成的矩形的最大面积. 思路:任意找四个点然后判断肯定是不行的,那么我们不妨来想一想矩形的性质.比如,对角线的交点是两条对角线的中点,对角线相等.这样的话只要找到一对线段,使得他们的中点相同,并且长度相同,那么这两个对角线一定能够组成一个矩形.只有就可以利用叉积求出面积了. 比较坑的一点是,这个题万万不能用double,因为有一个点专门卡double.可以尝试用long double,最好还是避免精度问题,统一用整数. CODE: #include <cs

●BZOJ 2329 [HNOI2011]括号修复.cpp

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一个Replace(替换)操作, 然后就要主要lazy标记之间的影响了. 1).Replace可以直接覆盖另外两个标记, 2).当已经有Replace标记,再覆盖Invert标记时,直接把Replace标记取反即可;在覆盖Swap标记时,Replace标记不变. 代码: #include<cstdio