您的位置:首页 > 其它

【BZOJ-2329】[HNOI2011] 括号修复

2018-02-26 20:32 369 查看
题目链接

题目描述

现在给你一个长度为 N 的由‘(‘和‘)’组成的字符串,位置标号从 1 到 N。对这个字符串有下列四种操作:

Replace a b c:将[a,b]之间的所有括号改成 c。例如:假设原来的字符串为:))())())(,那么执行操作 Replace 2 7 ( 后原来的字符串变为:)(((((()(。

Swap a b:将[a,b]之间的字符串翻转。例如:假设原来的字符串为:))())())(,那么执行操作 Swap 3 5 后原来的字符串变为:))))(())(。

Invert a b:将[a,b]之间的‘(’变成‘)’,‘)’变成‘(’。例如:假设原来的字符串为:))())())(,那么执行操作 Invert 4 8 后原来的字符串变为:))((()(((。

Query a b:询问[a,b]之间的字符串至少要改变多少位才能变成合法的括号序列。改变某位是指将该位的‘(’变成‘)’或‘)’变成‘(’。

(合法就是符合日常书写)

题解

首先一个括号序列如 ())()((()) ,中间已经抵消的可以去掉,变成: )(

先来研究一下对于n个” )” ,和m个 “(” 的最小修改次数

首先(m+n) 必为偶数,手玩可以发现:

ans=(n+1)/2+(m+1)/2ans=(n+1)/2+(m+1)/2

那么关键在于维护一个区间内的画简后的左右括号数。

既然左右要互相抵消,不妨我们设”(“为1,”)”为-1。

对于括号序列 ())()((())

假设我们从左到右,依次记录sum,那么就是:

1 0 -1 0 -1 0 1 2 1 0

发现最后左括号数是最小前缀的绝对值?

再从右到左:

-1 -2 -1 0 1 0 1 -1 -2 -1

发现右括号数是最大后缀?

(众人:好像是这么回事(雾))

于是就显然是这样了,维护最小前缀和最大后缀。

但是由于翻转操作的存在,似乎还要记录最小后缀和最大前缀,这样翻转时swap一下就行了 OVO

Splay搞起来就好了。

邻外这里操作较多,建议都写一个函数,方便pushdown()pushdown()(自己想想下放顺序)

代码如下(全写的指针···):

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
#define ls son[0]
#define rs son[1]
#define __ NULL
#define get_size(a) (a==__? 0:a->size)
#define get_son(a) (a->fa->rs==a)
#define get_min_l(a) (a==__? 0:a->min_l)
#define get_max_r(a) (a==__? 0:a->max_r)
#define get_min_r(a) (a==__? 0:a->min_r)
#define get_max_l(a) (a==__? 0:a->max_l)
#define get_sum(a) (a==__? 0:a->sum)
struct node{
int size;int x;
int min_l,max_r,sum;
int max_l,min_r;
int rp;bool sp;
bool ip;
node* fa;node* son[2];
node(){size=1;x=min_l=max_r=sum=0;fa=ls=rs=__;rp=sp=ip=0;max_l=min_r=0;}
}*rt;
int n,m;
const int N=1e5+100;
int opp
;
inline void Swap(register node*);
inline void Invert(register node*);
inline void Replace(register node*,register int);
inline void updata(node* p)
{
if(p==__) return;
p->size=1+get_size(p->ls)+get_size(p->rs);
p->sum=get_sum(p->ls)+get_sum(p->rs)+p->x;
p->min_l=min(get_min_l(p->ls),get_sum(p->ls)+p->x+get_min_l(p->rs));
p->max_r=max(get_max_r(p->rs),get_sum(p->rs)+p->x+get_max_r(p->ls));
p->max_l=max(get_max_l(p->ls),get_sum(p->ls)+p->x+get_max_l(p->rs));
p->min_r=min(get_min_r(p->rs),get_sum(p->rs)+p->x+get_min_r(p->ls));
}
inline void push_down(node* p)
{
if(p==__) return;
if(p->sp!=0){
Swap(p->ls);Swap(p->rs);p->sp=0;
}
if(p->rp!=0){
register int op=p->rp;
Replace(p->ls,op);Replace(p->rs,op);
p->rp=0;
}
if(p->ip!=0){
Invert(p->ls);Invert(p->rs);
p->ip=0;
}
return ;
}
inline void rotate(node* p)
{
register int k=get_son(p);
register node* q=p->fa;
push_down(q);push_down(p);
q->son[k]=p->son[k^1];
if(p->son[k^1]!=__) p->son[k^1]->fa=q;
if(q->fa!=__) q->fa->son[get_son(q)]=p;
p->fa=q->fa;
q->fa=p;
p->son[k^1]=q;
updata(q);
return ;
}
inline void Splay(node* p,node* goal)
{
if(p==goal) return;
if(goal==__) rt=p;
while(p->fa!=goal){
if(p->fa->fa==goal) {rotate(p);break;}
if(get_son(p)==get_son(p->fa)) rotate(p->fa),rotate(p);
else rotate(p),rotate(p);
}
updata(p);
return ;
}
inline int input()
{
char ch=getchar();while(ch!='('&&ch!=')') ch=getchar();
return ch=='('? 1:-1;
}
inline void build(node* &p,int l,int r)
{
if(l>r) return;
p=new node();
register int mid=l+r>>1;
p->x=opp[mid];p->min_l=min(0,p->x);p->max_r=max(0,p->x);
p->sum=p->x;p->max_l=p->max_r;p->min_r=p->min_l;
build(p->ls,l,mid-1);
build(p->rs,mid+1,r);
if(p->ls!=__) p->ls->fa=p;//!!
if(p->rs!=__) p->rs->fa=p;//!!
updata(p);
}
inline node* Find(int x)
{
if(x<1||x>n) return __;
register node* p=rt;
while(x&&p!=__){
push_down(p);
register int sz=get_size(p->ls);
if(sz>=x) p=p->ls;
else {x-=sz+1;if(!x) return p;p=p->rs;}
}
return p;
}
node *L,*R;
inline node* Get(register int l,register int r)
{
L=Find(l-1);R=Find(r+1);
register node* p=__;
if(L==__&&R==__) p=rt;
else if(L==__) Splay(R,__),p=rt->ls;
else if(R==__) Splay(L,__),p=rt->rs;
else Splay(L,__),Splay(R,rt),p=rt->rs->ls;
return p;
}
inline void Replace(register node* p,register int op)
{
if(p==__) return;
p->ip=0;//都改成一个东西了就不要反转了
p->x=op;p->sum=op*p->size;
p->min_l=min(0,p->sum);
p->max_r=max(0,p->sum);
p->max_l=p->max_r;
p->min_r=p->min_l;
p->rp=op;
}
inline void Swap(register node* p)
{
if(p==__) return;
p->sp^=1;
swap(p->ls,p->rs);
swap(p->max_l,p->max_r);
swap(p->min_l,p->min_r);
}
inline void Invert(register node* p)
{
if(p==__) return;
p->ip^=1;p->sum=~p->sum+1;p->x=~p->x+1;
swap(p->min_l,p->max_l);swap(p->min_r,p->max_r);
p->min_l=~p->min_l+1;p->max_l=~p->max_l+1;
p->min_r=~p->min_r+1;p->max_r=~p->max_r+1;//反转了就取个相反数即可
return ;
}
inline int Query(register node* p)
{
return ((p->max_r+1>>1)-(p->min_l-1)/2);
}
int main()
{
n=read();m=read();for(int i=1;i<=n;i++) opp[i]=input();
build(rt,1,n);
register int l,r;
for(register int i=1;i<=m;i++){
char ch=getchar();
while(ch!='R'&&ch!='Q'&&ch!='S'&&ch!='I') ch=getchar();
l=read();r=read();
register node* p=Get(l,r);
if(ch=='R') Replace(p,input());
else if(ch=='S') Swap(p);
else if(ch=='I') Invert(p);
else printf("%d\n",Query(p));
if(R!=__) updata(R);
if(L!=__) updata(L);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: