您的位置:首页 > 其它

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

2018-02-01 21:27 316 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=2329

需要改变的括号序列一定长这样 :)))(((

最少改变次数= 多余的‘)’/2 【上取整】 + 多余的‘(’ /2 【上取整】

把 ‘)’ 看做1,‘(’ 看做-1

那么最少改变次数=最大前缀和/2 【上取整】+ 最小后缀和/2 【上取整】

覆盖标记的优先级高于翻转标记和取反标记

即下放覆盖标记时,同时清空翻转标记和取反标记

且先下放覆盖标记

翻转:

最大前缀和 和 最大后缀和 交换

最小前缀和 和 最小后缀和 交换

取反:

最大前缀和 和 最小前缀和 交换,同时取反

最大后缀和 和 最小后缀和 交换,同时取反

最大XX和的下界为0,最小XX和的上界为0

因为最大XX和实际是多余的‘)’数量

最小XX和的相反数实际是多余的‘(’数量

数量不能为负数

注意点:

1、增加了首尾两个虚拟节点后,数组要多开2

2、平衡树每个节点由三部分组成,左子树、自己、右子树,打取反标记的时候不要忘记给自己取反

#include<cstdio>
#include<cstdlib>
#include<iostream>

using namespace std;

#define N 100003

char ss
;
int a
;

int root,tot;

int st
;

bool rev
,inv
;
int tag
;
int pre
,suf
;
int sum
;
int pri
,val
;

int siz
,ch
[2];

int tmp;

void read(int &x)
{
x=0; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

inline int &max(int &a,int &b) { return a>b ? a : b; }
inline int &min(int &a,int &b) { return a<b ? a : b; }

void update(int x)
{
int l=ch[x][0],r=ch[x][1];
siz[x]=siz[l]+siz[r]+1;
sum[x]=sum[l]+sum[r]+val[x];
pre[x]=max(pre[l],sum[l]+pre[r]+val[x]);
pre[x]=max(pre[x],sum[l]+val[x]);
suf[x]=max(suf[r],sum[r]+suf[l]+val[x]);
suf[x]=max(suf[x],sum[r]+val[x]);
}

int newnode(int v)
{
val[++tot]=sum[tot]=v;
pre[tot]=suf[tot]=max(0,val[tot]);
sum[tot]=val[tot];
siz[tot]=1;
pri[tot]=rand();
return tot;
}

int build(int l,int r)
{
int top=0; int last,now;
for(int i=l;i<=r;++i)
{
now=newnode(a[i]);
last=0;
while(top && pri[now]<pri[st[top]])
{
update(st[top]);
last=st[top--];
}
if(top) ch[st[top]][1]=now;
ch[now][0]=last;
st[++top]=now;
}
while(top) update(st[top--]);
return st[1];
}

void down(int x)
{
int l=ch[x][0],r=ch[x][1];
if(tag[x])
{
if(l)
{
val[l]=tag[x];
sum[l]=tag[x]*siz[l];
pre[l]=suf[l]=max(0,sum[l]);
rev[l]=inv[l]=false;
tag[l]=tag[x];
}
if(r)
{
val[r]=tag[x];
sum[r]=tag[x]*siz[r];
pre[r]=suf[r]=max(0,sum[r]);
rev[r]=inv[r]=false;
tag[r]=tag[x];
}
tag[x]=0;
}
if(rev[x])
{
if(l)
{
swap(pre[l],suf[l]);
swap(ch[l][0],ch[l][1]);
rev[l]^=1;
}
if(r)
{
swap(pre[r],suf[r]);
swap(ch[r][0],ch[r][1]);
rev[r]^=1;
}
rev[x]^=1;
}
if(inv[x])
{
if(l)
{
tmp=pre[l];
pre[l]=max(0,-(sum[l]-suf[l]));
suf[l]=max(0,-(sum[l]-tmp));
sum[l]=pre[l]+min(0,-sum[l]-pre[l]);
val[l]=-val[l];
inv[l]^=1;
}
if(r)
{
tmp=pre[r];
pre[r]=max(0,-(sum[r]-suf[r]));
suf[r]=max(0,-(sum[r]-tmp));
sum[r]=pre[r]+min(0,-sum[r]-pre[r]);
val[r]=-val[r];
inv[r]^=1;
}
inv[x]^=1;
}
}

void split(int now,int k,int &x,int &y)
{
if(!now) x=y=0;
else
{
down(now);
if(k<=siz[ch[now][0]])
{
y=now;
split(ch[now][0],k,x,ch[now][0]);
}
else
{
x=now;
split(ch[now][1],k-siz[ch[now][0]]-1,ch[now][1],y);
}
update(now);
}
}

int merge(int x,int y)
{
if(x) down(x);
if(y) down(y);
if(!x || !y) return x+y;
if(pri[x]<pri[y])
{
ch[x][1]=merge(ch[x][1],y);
update(x);
return x;
}
else
{
ch[y][0]=merge(x,ch[y][0]);
update(y);
return y;
}
}

int main()
{
int n,m;
read(n); read(m);
scanf("%s",ss+2);
for(int i=2;i<=n+1;++i)
if(ss[i]==')') a[i]=1;
else a[i]=-1;
root=build(1,n+2);
int l,r; char s[10],cc[3];
int a,b,c,d,e;
while(m--)
{
scanf("%s",s);
read(l); read(r);
l++; r++;
split(root,r,a,b);
split(a,l-1,c,d);
if(s[0]=='R')
{
scanf("%s",cc);
e= cc[0]==')' ? 1 : -1;
tag[d]=e;
val[d]=e;
sum[d]=e*siz[d];
pre[d]=suf[d]=max(0,sum[d]);
rev[d]=inv[d]=false;
}
else if(s[0]=='S')
{
rev[d]=true;
swap(ch[d][0],ch[d][1]);
swap(pre[d],suf[d]);
}
else if(s[0]=='I')
{
inv[d]=true;
tmp=pre[d];
pre[d]=max(0,-(sum[d]-suf[d]));
suf[d]=max(0,-(sum[d]-tmp));
sum[d]=pre[d]+min(0,-sum[d]-pre[d]);
val[d]=-val[d];
}
else printf("%d\n",(pre[d]+1)/2+(-sum[d]+pre[d]+1)/2);
root=merge(merge(c,d),b);
}
}


2329: [HNOI2011]括号修复

Time Limit: 40 Sec Memory Limit: 128 MB
Submit: 1229 Solved: 580
[Submit][Status][Discuss]

Description

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: