Bzoj2329: [HNOI2011]括号修复

题面

传送门

Sol

答案就是去掉匹配的括号后的左边右括号个数 /2 / 2 取下整和右边左括号个数 /2 / 2 取下整

维护:
( ( 1 ) ) 1,最大的前缀和就是左边右括号的个数
最小的的后缀和的相反数就是右边左括号的个数

因为要支持取反,翻转等操作
我们要维护左边最大最小,右边最大最小,子树和,子树大小

然后套 Splay S p l a y 模板

# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

template <class Int>
IL void Input(RG Int &x){
    RG int z = 1; RG char c = getchar(); x = 0;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    x *= z;
}

const int maxn(1e5 + 5);
typedef int Arr[maxn];

int n, m, rt;
Arr lmn, rmn, lmx, rmx, size, val, sum, fa, inv, rev, cov, ch[2];
char s[maxn];

# define ls ch[0][x]
# define rs ch[1][x]

IL int Son(RG int x){
    return ch[1][fa[x]] == x;
}

IL void Update(RG int x){
    lmn[x] = min(lmn[ls], lmn[rs] + val[x] + sum[ls]);
    lmx[x] = max(lmx[ls], lmx[rs] + val[x] + sum[ls]);
    rmn[x] = min(rmn[rs], rmn[ls] + val[x] + sum[rs]);
    rmx[x] = max(rmx[rs], rmx[ls] + val[x] + sum[rs]);
    size[x] = size[ls] + size[rs] + 1;
    sum[x] = sum[ls] + sum[rs] + val[x];
}

IL void Rotate(RG int x){
    RG int y = fa[x], z = fa[y], c = Son(x);
    if(z) ch[Son(y)][z] = x; fa[x] = z;
    ch[c][y] = ch[!c][x], fa[ch[c][y]] = y;
    ch[!c][x] = y, fa[y] = x;
    Update(y);
}

IL void Splay(RG int x, RG int ff){
    for(RG int y = fa[x]; y != ff; Rotate(x), y = fa[x])
        if(fa[y] != ff) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
    if(!ff) rt = x;
    Update(x);
}

IL void Build(RG int l, RG int r, RG int ff){
    if(l > r) return;
    RG int mid = (l + r) >> 1;
    fa[mid] = ff;
    if(ff) ch[ff < mid][ff] = mid;
    else rt = mid;
    Build(l, mid - 1, mid), Build(mid + 1, r, mid);
    Update(mid);
}

IL void Invert(RG int x){
    if(!x) return;
    inv[x] ^= 1, sum[x] = -sum[x], val[x] = -val[x];
    swap(lmx[x], lmn[x]), swap(rmx[x], rmn[x]);
    lmx[x] = -lmx[x], rmx[x] = -rmx[x];
    lmn[x] = -lmn[x], rmn[x] = -rmn[x];
}

IL void Cover(RG int x, RG int op){
    if(!x) return;
    cov[x] = op, inv[x] = rev[x] = 0;
    sum[x] = op * size[x], val[x] = op;
    lmx[x] = rmx[x] = max(0, sum[x]);
    lmn[x] = rmn[x] = min(0, sum[x]);
}

IL void Reverse(RG int x){
    if(!x) return;
    rev[x] ^= 1, swap(ls, rs);
    swap(lmx[x], rmx[x]), swap(lmn[x], rmn[x]);
}

IL void Pushdown(RG int x){
    if(cov[x]) Cover(ls, cov[x]), Cover(rs, cov[x]), cov[x] = 0;
    if(rev[x]) Reverse(ls), Reverse(rs), rev[x] ^= 1;
    if(inv[x]) Invert(ls), Invert(rs), inv[x] ^= 1;
}

IL int Kth(RG int x, RG int k){
    while(233){
        RG int sz = size[ls];
        Pushdown(x);
        if(k <= sz) x = ls;
        else if(k == sz + 1) return x;
        else k -= sz + 1, x = rs;
    }
}

IL int Split(RG int l, RG int r){
    RG int x = Kth(rt, l); Splay(x, 0);
    RG int y = Kth(rt, r + 2); Splay(y, x);
    return ch[0][y];
}

char op[10], v;

int main(RG int argc, RG char* argv[]){
    Input(n), Input(m), scanf(" %s", s + 2);
    for(RG int i = 2; i <= n + 1; ++i) val[i] = s[i] == '(' ? -1 : 1;
    Build(1, n + 2, 0);
    for(RG int i = 1, l, r, x; i <= m; ++i){
        scanf(" %s", op), Input(l), Input(r);
        x = Split(l, r);
        if(op[0] == 'R') scanf(" %c", &v), Cover(x, v == '(' ? -1 : 1);
        else if(op[0] == 'S') Reverse(x);
        else if(op[0] == 'I') Invert(x);
        else printf("%d\n", ((lmx[x] + 1) >> 1) + ((1 - rmn[x]) >> 1));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值