UESTC 94 Bracket Sequence(线段树的区间更新)

本文介绍了一种使用线段树解决括号序列的操作与查询问题的方法,包括设置、反转括号序列及判断序列合法性等操作。通过定义特定的数据结构和算法实现高效的区间更新和查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

有T(T<10)组测试数据,然后有一个数字N(N<100000),接下来的一行里有N个字符,每个字符是’(‘或’)’,现在有三种操作
(1)”set l r c”,表示将区间[l,r]里的所有元素改变为c,c是’(‘或’)’的其中一种。
(2)”reverse l r”,表示将区间[l,r]里的’(‘与’)’对调。
(3)”query l r”,表示查询区间[l,r]是否为一个合法的括号序列。

解析:

如果我们可以令’(‘为-1,而’)’为1,注意到如果在区间[l,r]里从l出发不断向后扫直到r,同时求和,在这个过程中,如果和的最大值是小于等于0的,并且最后的和是等于0的,那么这个序列是合法的,即输出”YES”。

那么这就要求在线段树的结点中要保存一个sumv域和maxv域(即最大值),对于操作”set”和操作”reverse”分别有两个延迟操作与之对应,即cover和XOR。因为操作”reverse”,要求对换1和-1,则为了维护max域,所以在线段树的结点中多增加一个域,min(表示最小值),这样在进行操作”reverse”时,就可以通过取反操作,得到这个区间的max。

当要向下传递延迟操作的时候,要先传递”set”操作的标记,即cover,后传递XOR。因为对一个区间进行”set”操作的时候,会将之前的”reverse”操作的标记置0(因为之前的”reverse”操作是失效的),如果一个区间同时有cover和XOR,那么一个是”set”操作先到达这个区间,然后”reverse”操作再到达这个区间。

区间合并的时候,维护当前区间的min域,维护的是从左儿子的min域 和 左儿子的sum加上右儿子的min中取最小值。max域的更新也类似。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 1000005;
char str[N];
int n;

int cover[N<<2], XOR[N<<2];
int maxv[N<<2], minv[N<<2], sumv[N<<2];

void setValue(int o, int L, int R, int val) {
    cover[o] = val;
    int len = (R - L + 1), tmp = len * val;
    sumv[o] = tmp;
    maxv[o] = max(tmp, 0);
    minv[o] = min(tmp, 0);
    XOR[o] = 0;
}

void reversal(int o) {
    if(cover[o]) {
        cover[o] *= -1;
        sumv[o] *= -1;
        XOR[o] = 0;
    } else {
        XOR[o] ^= 1;
        sumv[o] *= -1;
    }
    int a = -maxv[o], b = -minv[o];
    maxv[o] = max(a, b);
    minv[o] = min(a, b);
}

void pushDown(int o, int L, int R) {
    int M = (L + R)/2;
    if(cover[o]) {
        setValue(lson, cover[o]);
        setValue(rson, cover[o]);
        cover[o] = 0;
    }
    if(XOR[o]) {
        reversal(ls);
        reversal(rs);
        XOR[o] = 0;
    }
}

void pushUp(int o) {
    sumv[o] = sumv[ls] + sumv[rs];
    minv[o] = min(minv[ls], sumv[ls] + minv[rs]);
    maxv[o] = max(maxv[ls], sumv[ls] + maxv[rs]);
}

void build(int o, int L, int R) {
    XOR[o] = cover[o] = 0;
    if(L == R) {
        int val;
        val = (str[L] == '(') ? -1 : 1;
        setValue(o, L, R, val);
        return ;
    }
    int M = (L + R)/2;
    build(lson);
    build(rson);
    pushUp(o);
}

void modify(int o, int L, int R, int ql, int qr, int val) {
    if(ql <= L && R <= qr) {
        if(val == 2) reversal(o);
        else setValue(o, L, R, val);
        return ;
    }
    pushDown(o, L, R);
    int M = (L + R)/2;
    if(ql <= M) modify(lson, ql, qr, val);
    if(qr > M) modify(rson, ql, qr, val);
    pushUp(o);
}

void query(int o, int L, int R, int ql, int qr, int& _sum, int& _max) {
    if(ql <= L && R <= qr) {
        _max = maxv[o], _sum = sumv[o];
        return ;
    }
    pushDown(o, L, R);
    int M = (L + R)/2;
    int suml = 0, sumr = 0, maxl = 0, maxr = 0;
    if(ql <= M) query(lson, ql, qr, suml, maxl);
    if(qr > M) query(rson, ql, qr, sumr, maxr);
    _sum = suml + sumr;
    _max = max(maxl, suml + maxr);
}

void solve() {
    int q, ql, qr, val;
    char cmd[10], ch[10];
    scanf("%d", &q);
    while(q--) {
        scanf("%s", cmd);
        if(cmd[0] == 's') {
            scanf("%d%d%s", &ql, &qr, ch);
            val = (ch[0] == '(') ? -1 : 1;
            modify(1, 0, n-1, ql, qr, val);
        }else if(cmd[0] == 'r') {
            scanf("%d%d", &ql, &qr);
            modify(1, 0, n-1, ql, qr, 2);
        }else {
            scanf("%d%d", &ql, &qr);
            int _sum = 0, _max = 0;
            query(1, 0, n-1, ql, qr, _sum, _max);
            printf("%s\n", (_max <= 0 && _sum == 0) ? "YES" : "NO");
        }
    }
}

int main() {
    int T, cas = 1;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        scanf("%s", str);
        build(1, 0, n-1);
        printf("Case %d:\n", cas++);
        solve();
        puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值