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

题目链接

题目描述

现在给你一个长度为 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) 必为偶数,手玩可以发现:

a n s = ( 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搞起来就好了。
邻外这里操作较多,建议都写一个函数,方便 p u s h d o w n ( ) (自己想想下放顺序)

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

#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[N];
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);
    }
}

猜你喜欢

转载自blog.csdn.net/element_hero/article/details/79378771