您的位置:首页 > 其它

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

2018-01-30 22:01 429 查看
题面:

http://www.lydsy.com/JudgeOnline/problem.php?id=2329

思路:

显然,操作4中输出补全的最小费用是关键

这决定了我们不可能在splay上只维护1-2个值。

考虑一段括号序列,将其中所有合法序列删去以后,留下的一定是形如 ))))))((( 的序列

因此首先考虑将每段区间左侧不匹配的括号数和右侧不匹配的括号数记录下来,分别为 left[l,r] 和 right[l,r]

此时除了Invert操作以外已经可以满足

但是对于Invert操作,对于每一个括号取反,显然每边只记录一个是不够的。

考虑再次转化模型,将括号序列抽象化成数字的和

发现:一个匹配的括号序列中左括号等于右括号,一段缩过的序列(去掉了所有的合法序列)的左侧右括号数量和右侧左括号数量,恰等于左右括号数量的前缀和以及后缀和。

因此,将右括号 )视为-1,左括号( 视为+1,对每一段区间,记录其最小前缀和和最大后缀和,即为上文所述 left && right

同时,我们记录区间的最大前缀和和最小后缀和,作为Swap和Invert操作时候用。

对于Swap操作,即为整个序列翻转,那么其最大前缀和与最大后缀和交换,最小前缀和与最小后缀和交换

对于Invert操作,需要交换最大最小前缀和,以及最大最小后缀和,再将它们全部取反

因为每个括号取反以后,原来最小的前缀和对应的哪一个序列,现在具有所有前缀里面的最大值(在相反数意义下)

后缀同理

统计答案即为对于所求区间,求 (l1/2)+(r2/2) ,若l1,r2是奇数,则还需加二(额外费用)

综上所述,令每一个)为-1,每一个(为1,记录每一个区间的最小最大前缀和 l1,l2 以及最小最大后缀和 r1,r2,将整个序列放到splay上操作即可。

需要注意的是,更新区间全部刷成同一个值的lazy标记时,一定要同时去掉已有的invert标记,以防WA

Code:

/**************************************************************
Problem: 2329
User: dedicatus545
Language: C++
Result: Accepted
Time:10484 ms
Memory:6860 kb
****************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m,root,cnt;
int fa[100010],ch[100010][2],siz[100010];
int w[100010],l1[100010],l2[100010],r1[100010],r2[100010],sum[100010];
int rev[100010]={0},lazy[100010]={0},inv[100010]={0};
int x[100010];
//lazy==1:  (
//lazy==-1: )
void _swap(int &x,int &y){x^=y;y^=x;x^=y;}
int _max(int x,int y){return (x<y)?y:x;}
int _min(int x,int y){return (x>y)?y:x;}
void update(int x){
if(!x) return;
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+w[x];
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
l1[x]=_min(l1[ch[x][0]],sum[ch[x][0]]+w[x]+l1[ch[x][1]]);
l2[x]=_max(l2[ch[x][0]],sum[ch[x][0]]+w[x]+l2[ch[x][1]]);
r1[x]=_min(r1[ch[x][1]],sum[ch[x][1]]+w[x]+r1[ch[x][0]]);
r2[x]=_max(r2[ch[x][1]],sum[ch[x][1]]+w[x]+r2[ch[x][0]]);
}
void pushdown(int x,int t){
if(!x) return;
inv[x]=0;w[x]=t;lazy[x]=t;
if(~t){
sum[x]=siz[x];
l1[x]=r1[x]=0;
l2[x]=r2[x]=sum[x];
}
else{
sum[x]=~siz[x]+1;
l2[x]=r2[x]=0;
l1[x]=r1[x]=sum[x];
}
}
void pushrev(int x){
if(!x) return;
_swap(ch[x][0],ch[x][1]);
_swap(l1[x],r1[x]);
_swap(l2[x],r2[x]);
rev[x]^=1;
}
void pushinv(int x){
if(!x) return;
_swap(l1[x],l2[x]);
_swap(r1[x],r2[x]);
l1[x]=~l1[x]+1;l2[x]=~l2[x]+1;
r1[x]=~r1[x]+1;r2[x]=~r2[x]+1;
w[x]=~w[x]+1;sum[x]=~sum[x]+1;inv[x]^=1;
}
void push(int x){
if(!x) return;
if(rev[x]){
pushrev(ch[x][0]);
pushrev(ch[x][1]);
rev[x]=0;
}
if(lazy[x]){
pushdown(ch[x][0],lazy[x]);
pushdown(ch[x][1],lazy[x]);
lazy[x]=0;
}
if(inv[x]){
pushinv(ch[x][0]);
pushinv(ch[x][1]);
inv[x]=0;
}
}
int get(int x){return ch[fa[x]][1]==x;}
void rotate(int x){
int f=fa[x],ff=fa[f],son=get(x);
push(f);push(x);
ch[f][son]=ch[x][son^1];
if(ch[f][son]) fa[ch[f][son]]=f;
fa[f]=x;ch[x][son^1]=f;
fa[x]=ff;
if(ff) ch[ff][ch[ff][1]==f]=x;
update(f);update(x);
}
void splay(int x,int to){
if(x==to||fa[x]==to) return;
if(!to) root=x;
for(int f;(f=fa[x])&&f!=to;rotate(x))
if(fa[f]!=to)
rotate(get(f)==get(x)?f:x);
update(x);
}
int rank(int x,int pos){
push(pos);
if(siz[ch[pos][0]]+1==x){
splay(pos,0);return pos;
}
if(siz[ch[pos][0]]>=x) return rank(x,ch[pos][0]);
else return rank(x-siz[ch[pos][0]]-1,ch[pos][1]);
}
int build(int le,int ri,int f){
if(le>ri) return 0;
int mid=(le+ri)>>1,cur=++cnt;
//cout<<"build "<<le<<" "<<ri<<" "<<mid<<" "<<x[mid]<<"\n";
w[cur]=x[mid];fa[cur]=f;
ch[cur][0]=build(le,mid-1,cur);
ch[cur][1]=build(mid+1,ri,cur);
update(cur);return cur;
}
void change(int le,int ri,int t){
int x=rank(le,root),y=rank(ri+2,root);
splay(x,0);splay(y,root);
pushdown(ch[y][0],t);
update(y);update(x);
}
void reverse(int le,int ri){
int x=rank(le,root),y=rank(ri+2,root);
splay(x,0);splay(y,root);
pushrev(ch[y][0]);
update(y);update(x);
}
void invert(int le,int ri){
int x=rank(le,root),y=rank(ri+2,root);
splay(x,0);splay(y,root);
pushinv(ch[y][0]);
update(y);update(x);
}
int query(int le,int ri){
int x=rank(le,root),y=rank(ri+2,root);
splay(x,0);splay(y,root);
return ((r2[ch[y][0]]+1)>>1)-((l1[ch[y][0]]-1)/2);
}
void dfs(int u){
if(!u) return;
push(u);
dfs(ch[u][0]);
printf("%d %d %d %d\n",u,fa[u],ch[u][0],ch[u][1]);
printf("%d %d %d %d %d\n",w[u],l1[u],l2[u],r1[u],r2[u]);
dfs(ch[u][1]);
}
char s[100010];
int main(){
//    freopen("brackets.in","r",stdin);
//    freopen("brackets.out","w",stdout);
int i,t1,t2,t4;char t3;
n=read();m=read();
scanf("%s",s);
for(i=1;i<=n;i++) x[i]=((s[i-1]=='(')?1:-1);
root=build(0,n+1,0);
//dfs(root);printf("\n");
for(i=1;i<=m;i++){
scanf("%s",s);
if(s[0]=='R'){
t1=read();t2=read();t3=getchar();
while(t3!='('&&t3!=')') t3=getchar();
t4=((t3=='(')?1:-1);
change(t1,t2,t4);
}
if(s[0]=='I'){
t1=read();t2=read();
invert(t1,t2);
}
if(s[0]=='Q'){
t1=read();t2=read();
printf("%d\n",query(t1,t2));
}
if(s[0]=='S'){
t1=read();t2=read();
reverse(t1,t2);
}
//dfs(root);printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: