bzoj2329 [HNOI2011]括号修复

http://www.elijahqi.win/2018/01/25/bzoj2329/
题目描述

一个合法的括号序列是这样定义的:

空串是合法的。
如果字符串 S 是合法的,则(S)也是合法的。
如果字符串 A 和 B 是合法的,则 AB 也是合法的。

现在给你一个长度为 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]之间的字符串至少要改变多少位才能变成合法的括号序列。改变某位是指将该位的‘(’变成‘)’或‘)’变成‘(’。注意执行操作 Query 并不改变当前的括号序列。例如:假设原来的字符串为:))())())(,那么执行操作 Query 3 6

的结果为 2,因为要将位置 5 的‘)’变成‘(’并将位置 6 的‘(’变成‘)’。
输入输出格式

输入格式:

从文件input.txt中读入数据,输入文件的第一行是用空格隔开的两个正整数N和M,分别表示字符串的长度和将执行的操作个数。第二行是长度为N的初始字符串S。接下来的M行是将依次执行的M个操作,其中操作名与操作数之间以及相邻操作数之间均用空格隔开。30%的数据满足

N,M≤3000。100%的数据满足N,M≤100000。

输出格式:

输出文件 output.txt 包含 T 行,其中 T 是输入的将执行的 M 个操作中 Query 操作出现的次数。Query 操作的每次出现依次对应输出文件中的一行,该行只有一个非负整数,表示执行对应 Query 操作的结果,即:所指字符串至少要改变多少位才能变成合法的括号序列。输入数据

保证问题有解。
输入输出样例

输入样例#1: 复制

4 5
((((
Replace 1 2 )
Query 1 2
Swap 2 3
Invert 3 4
Query 1 4

输出样例#1: 复制

1
2

说明

样例解释:输入中有2个Query操作,所以输出有2行。执行第一个Query操作时的括号序列为))((,因改变第1位可使[1,2]之间的字符串变成合法的括号序列,故输出的第一行为1。执行第二个Query操作时的括号序列为)((),因要改变第1位和第2位才能使[1,4]之间的字符串变成合法的括号序列,故输出的第二行为2。

细节太多 蒟蒻我觉得讨论起来非常麻烦 不好想清楚 并且标记众多 需注意下放的时候的先后顺序(被坑死

首先括号序列:做过之前zjoi捉迷藏那道题 可以清楚的知道 我现在怎样维护括号序列了 那么就是维护一个a,b 那么这个a表示”)”这个括号的数量 b表示“(”这个括号的数量 那么我就可以知道 我需要输出的那个值就是(a+1)/2+(b+1)/2 这样的话就像线段树上 区间合并一样 左端点的b会和右端点的a消去 但是一开始我就是这么写 显然有问题 问题在哪里 因为尝试出例子画一画之后发现 我反转的时候因为信息不齐是错的 反转就是针对自己取反的那个操作 因为取反之后我的信息就改变了 比如对自己本身取反 可能直接都消没了 所以我需要维护两个值 1、现在序列的括号匹配值 2、 取反之后序列的括号匹配值 注意 在进行翻转的时候要针对我序列本身也要做一些取反的操作这时候我曾经的a,b现在变成了可以消去的部分 曾经可以消去的部分 现在变成了不可消去的部分 注意算一算他们的关系分类讨论下即可

注意下放的顺序 那个覆盖标记需要在最后下放 为什么 因为我一旦覆盖的话 我就会把其他两个标记清除那么如果我还存在其他的两个标记说明一定是覆盖之后造成的 如果我先下放覆盖再下放反转什么的操作 就会因为我主程序里先写的覆盖后写的反转等导致反转两次 没有反转很坑

#include<cstdio>
#include<algorithm>
#define N 110000
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return x*f; 
}//sw对应invert操作
int a[N],b[N],rev[N],sw[N],fa[N],c[N][2],v[N],l1[N],l2[N],r1[N],r2[N],size[N],tag[N],root,n,m; 
char op[10],s[N];// l1左边正常值l2左边反转值 r1右边正常值 r2右边反转值 
inline void update(int x){
    int l=c[x][0],r=c[x][1];
    size[x]=size[l]+size[r]+1;
    l1[x]=l1[l]+max(0,l1[r]-r1[l]+v[x]);r1[x]=r1[r]+max(0,r1[l]-l1[r]-v[x]);
    l2[x]=l2[l]+max(0,l2[r]-r2[l]-v[x]);r2[x]=r2[r]+max(0,r2[l]-l2[r]+v[x]);
}
inline void build(int f,int l,int r){
    if (l>r) return;int mid=l+r>>1;
    c[f][mid>f]=mid;fa[mid]=f;v[mid]=s[mid];
    build(mid,l,mid-1);build(mid,mid+1,r);update(mid);
}
inline void pushdown(int x){
    int l=c[x][0],r=c[x][1];
    if (sw[x]){
        v[l]=-v[l];tag[l]=-tag[l];swap(l1[l],l2[l]);swap(r1[l],r2[l]);sw[l]^=1;
        v[r]=-v[r];tag[r]=-tag[r];swap(l1[r],l2[r]);swap(r1[r],r2[r]);sw[r]^=1;
        sw[x]=0;    
    }
    if (rev[x]){
        swap(c[l][0],c[l][1]);swap(l1[l],r2[l]);swap(l2[l],r1[l]);rev[l]^=1;
        swap(c[r][0],c[r][1]);swap(l1[r],r2[r]);swap(l2[r],r1[r]);rev[r]^=1;
        rev[x]=0;
    }
    if (tag[x]){
        tag[l]=tag[r]=v[l]=v[r]=tag[x];
        if (tag[x]==1){
            l1[l]=r2[l]=size[l];l2[l]=r1[l]=0;
            l1[r]=r2[r]=size[r];l2[r]=r1[r]=0;
        }else{
            l2[l]=r1[l]=size[l];l1[l]=r2[l]=0;
            l2[r]=r1[r]=size[r];l1[r]=r2[r]=0;
        }tag[x]=0;
    }
}
inline int find(int x,int sz){
    pushdown(x);int l=c[x][0],r=c[x][1];
    if (size[l]+1==sz) return x;
    if(sz<=size[l]) return find(l,sz);return find(r,sz-size[l]-1); 
}
inline void rotate(int x,int &tar){
    int y=fa[x],z=fa[y];
    if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
    int l=c[y][1]==x,r=l^1;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
    while(x!=tar){
        int y=fa[x],z=fa[y];
        if (y!=tar){
            if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
        }rotate(x,tar);
    }
}
inline int split(int x,int y){
    int xx=find(root,x),yy=find(root,y);
    splay(yy,root);splay(xx,c[root][0]);return c[xx][1]; 
}
inline void print(int x){
    pushdown(x);
    if (c[x][0]) print(c[x][0]);
    printf("%d %d %d %d %d %d\n",size[x],v[x],l1[x],r1[x],l2[x],r2[x]);
    if (c[x][1]) print(c[x][1]);
}
int main(){
    freopen("bzoj2329.in","r",stdin);
    n=read();m=read();scanf("%s",s+2);
    for (int i=2;i<=n+1;++i) s[i]=s[i]==')'?1:-1;
    build(0,1,n+2);root=n+3>>1;
    for (int i=1;i<=m;++i){
        scanf("%s",op);int x=read(),y=read(),tmp=split(x,y+2);
        if (op[0]=='R'){
            char ch[2];scanf("%s",ch);tag[tmp]=ch[0]==')'?1:-1;sw[tmp]=rev[tmp]=0;
            v[tmp]=tag[tmp];if (tag[tmp]==1) l1[tmp]=r2[tmp]=size[tmp],l2[tmp]=r1[tmp]=0;
            else r1[tmp]=l2[tmp]=size[tmp],r2[tmp]=l1[tmp]=0;update(fa[tmp]);update(root);
        }
        if (op[0]=='Q') printf("%d\n",((l1[tmp]+1)>>1)+(r1[tmp]+1>>1));
        if (op[0]=='S'){rev[tmp]^=1;swap(c[tmp][0],c[tmp][1]);swap(l1[tmp],r2[tmp]);swap(l2[tmp],r1[tmp]);update(fa[tmp]);update(root);}
        if (op[0]=='I'){sw[tmp]^=1;v[tmp]=-v[tmp];tag[tmp]=-tag[tmp];swap(l1[tmp],l2[tmp]);swap(r1[tmp],r2[tmp]);update(fa[tmp]);update(root);}
    //  print(root);puts("");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值