uestc 1546 括号序列 区间线段树

/*
    区间线段树  区间覆盖   括号序列  lazy


    题意:给一串括号序列,问[l,r]的括号序列是否合法。合法的定义:1,Empty 2,S合法,则(S)合法 3,A和B合法,则AB合法。有两种操作,一种一般区间修改(reverse, set),还有Query.




    思路:之前一遇到括号序列就跪,因为我到现在都搞不清楚what is regular brackets sequence...
          所以在大牛blog上看到下面这句话的时候心情很激动~~from : http://hi.baidu.com/zyz913614263/item/ed68843a6839ecd2392ffa2b
           *** "把左括号当做-1,右括号当做1,对于一个区间,只要从左到右的和的最大值为0,并且区间的和为0,则这个区间就是完全匹配的" ***




          知道上面这个定理后,接下来都是自己写的。这道题细节还是挺多的。




          (1)在Update和Query下子节点时,都要先put_down。
          (2)我的lazy标记只有一个,后来看别人的代码时发现他们用了两个,一个is_reverse, 一个is_set。其实可以合成一个的。
          (3)细节多WA在有lazy来时和put_down的时候的处理:保存lazy时要更新节点属性put_self。刚开始时我把更新lazy值和更新节点属性分开了,后来发现不对,前后的lazy值会影响节点属性的更新,所以干脆都扔到change()里,方便多了。






           *** "把左括号当做-1,右括号当做1,对于一个区间,只要从左到右的和的最大值为0,并且区间的和为0,则这个区间就是完全匹配的" ***

*/


//Bracket Sequence UESTC 1546
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define     debug       printf("!\n")
#define     MAXN        100005
#define     MID(x, y)   (((x)+(y)) >> 1)
#define     L(x)        ((x)<<1)
#define     R(x)        (((x)<<1)|1)

typedef pair<int,int> Pair;
struct Node {
    int l,r,min,max,end;
    char lazy;
} f[MAXN << 2];
char str[100005];
int n;

void Update(int , int , int , char);
void put_self(int u, char op)           //更新节点u
{
    if(op == '(' || op == ')') {
        int tmp = (op == '(' ? -1 : 1);
        f[u].end = tmp * (f[u].r - f[u].l + 1);
        f[u].min = min(tmp, f[u].end);
        f[u].max = max(tmp, f[u].end);
    } else {
        f[u].end = - f[u].end;
        int tmp = f[u].max;
        f[u].max = -f[u].min;
        f[u].min = -tmp;
    }
}
void change(int u, char arrive)     //遇到修改[l,r]操作时边lazy,边更新自己的属性(max,min,end)
{
    if(arrive == '(' || arrive == ')') {
        put_self(u, arrive);
        f[u].lazy = arrive;
    } else if(arrive == 'r') {
        put_self(u, 'r');
        if(f[u].lazy == 'r') f[u].lazy = '\0';
        else if(f[u].lazy == '\0') f[u].lazy = 'r';
        else f[u].lazy = (f[u].lazy == ')' ?  '(' : ')');
    }
}
void put_up(int u)
{
    Node & ll = f[L(u)];
    Node & rr = f[R(u)];
    f[u].end = ll.end + rr.end;
    f[u].max = max(ll.max, ll.end+rr.max);
    f[u].min = min(ll.min, ll.end+rr.min);
}

void put_down(int u)
{
    int mid = MID(f[u].l, f[u].r);
    Update(L(u), f[u].l, mid, f[u].lazy);
    Update(R(u), mid+1, f[u].r, f[u].lazy);
    f[u].lazy = '\0';
}
void build(int u, int l, int r)
{
    f[u].l = l, f[u].r = r, f[u].lazy = '\0';    
    if(l == r) {
        f[u].min = f[u].max = f[u].end = (str[l] == '(' ? -1 : 1);      //小错误大烦恼,忘了初始化min...debug了好久
        return ;
    }
    int mid = MID(l, r);
    build(L(u), l, mid);
    build(R(u), mid+1, r);
    put_up(u);
}
Pair Query(int u, int l, int r)
{
    if(l == f[u].l && f[u].r == r) {
        return Pair (f[u].end, f[u].max);
    }
    if(f[u].lazy != '\0') put_down(u);          //所以说,小错误有大关系...漏了判断就得debug很久
    int mid = MID(f[u].l, f[u].r);
    if(r <= mid) return Query(L(u), l, r);
    else if(mid < l) return Query(R(u), l, r);
    else {
        Pair p1 = Query(L(u), l, mid) , p2 = Query(R(u), mid+1, r);
        return Pair(p1.first + p2.first, max(p1.second, p1.first + p2.second));
    }
}
void Update(int u, int l, int r, char op)
{
    if(l == f[u].l && f[u].r == r) {
        change(u, op);          //把lazy的更新,max/end的更新放到change里了
        return ;
    }
    if(f[u].lazy != '\0')put_down(u);
    int mid = MID(f[u].l, f[u].r);
    if(r <= mid) Update(L(u), l, r, op);
    else if(mid < l) Update(R(u), l, r, op);
    else Update(L(u), l, mid, op), Update(R(u), mid+1, r, op);
    put_up(u);
}
int main()
{
    int cases, Cas = 0, query, l, r;
    char op[10];
    scanf("%d", &cases);
    while(cases--) {
        printf("Case %d:\n", ++Cas);
        scanf("%d%s%d", &n, str, &query);
        build(1, 0, n-1);
        while(query--) {
            scanf("%s%d%d\n", op, &l, &r);
            if(op[0] == 'q') {
                Pair p = Query(1, l,r);
                puts(p.first == 0 && p.second < 1 ? "YES" : "NO");
//                printf("!! %d  %d\n", p.first, p.second);
            } else if(op[0] == 's') {
                scanf("%s", str);
                Update(1, l, r, str[0]);
            } else Update(1, l, r, 'r');
        }
        puts("");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值