题目大意:给出一个括号序列,问一段区间最少需要修改多少括号使得这一段括号变成一段完整的括号序列。
思路:题解见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;
}BZOJ 2329 HNOI 2011 括号修复 Splay维护最大连续子段和
原文地址:http://blog.csdn.net/jiangyuze831/article/details/42526981