HDOJ 5217 Brackets(zkw线段树模板+单点更新)

题目大意:

给定一串括号,现在有两种操作:

1. 翻转第x个括弧;

2. 对于区间[l, r]内,消去所有匹配的扩后后,查询消除后第k个括弧原来的位置是第几,若k大于消除后的区间长度,输出-1.


正统线段树t了,用了点黑魔法!


#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 200100

inline int RD(int &x)
{
        x = 0;
        char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') exit(0); ch = getchar(); if(ch == EOF) return 0; }
        while(isdigit(ch)) { x *= 10; x += ch - '0'; ch = getchar(); }
        return 1;
}

struct Node
{
    int l, r, mate;
    Node() {}
    Node(int _l, int _r, int _m): l(_l), r(_r), mate(_m) {}
};

int M;
Node tree[MAXN << 2];
char str[MAXN];

void Init(int n)
{
    n <<= 2;
    for(int i = 1; i <= n; i++) tree[i] = Node(0, 0, 0);
}

void Pushup(int rt)
{
    int t = min(tree[rt << 1].l, tree[rt << 1 | 1].r);
    tree[rt].mate = tree[rt << 1].mate + tree[rt << 1 | 1].mate + t;
    tree[rt].l = tree[rt << 1].l + tree[rt << 1 | 1].l - t;
    tree[rt].r = tree[rt << 1].r + tree[rt << 1 | 1].r - t;
}

void Build(int n)
{
    for(M = 1; M <= n + 1; M <<= 1) ;
    for(int i = M + 1; i <= M + n; i++)
    {
        if(str[i - M] == '(') tree[i].l++;
        if(str[i - M] == ')') tree[i].r++;
    }
    for(int i = M - 1; i; i--) Pushup(i);
}

void Update(int p)
{
    p += M;
    swap(tree[p].l, tree[p].r);
    for(p >>= 1; p; p >>= 1) Pushup(p);
}

Node Query(int s, int t)
{
    Node lch(0, 0, 0), rch(0, 0, 0);
    int ltot, rtot, mtot, mt;
    for(s += M - 1, t += M + 1; s ^ t ^ 1; s >>=1 , t >>= 1)
    {
        if(~s & 1)
        {
            mt = min(lch.l, tree[s ^ 1].r);
            ltot = lch.l + tree[s ^ 1].l - mt;
            rtot = lch.r + tree[s ^ 1].r - mt;
            mtot = lch.mate + tree[s ^ 1].mate + mt;
            lch = Node(ltot, rtot, mtot);
        }
        if(t & 1)
        {
            mt = min(rch.r, tree[t ^ 1].l);
            ltot = rch.l + tree[t ^ 1].l - mt;
            rtot = rch.r + tree[t ^ 1].r - mt;
            mtot = rch.mate + tree[t ^ 1].mate + mt;
            rch = Node(ltot, rtot, mtot);
        }
    }
    mt = min(lch.l, rch.r);
    ltot = lch.l + rch.l - mt;
    rtot = lch.r + rch.r - mt;
    mtot = lch.mate + rch.mate + mt;
    return Node(ltot, rtot, mtot);
}

int find(int s, int e, int l, int r, int k)
{
    int m, t, ck;
    Node lch, rch;
    while(l < r)
    {
        m = (l + r) >> 1;
        lch = Query(s, m);
        rch = Query(m + 1, e);
        t = min(lch.l, rch.r);
        ck = m - s + 1 - lch.mate * 2 - t;
        if(ck >= k) r = m;
        if(ck <  k) l = m + 1;
    }
    return r;
}

int n, q, op, x, l, r, k, m;
int main()
{
//    freopen("1004.in", "r", stdin);

    int cas; scanf("%d", &cas);
    while(cas--)
    {
        scanf("%d%d", &n, &q);
        scanf("%s", str + 1);
        Init(n);
        Build(n);
        while(q--)
        {
            scanf("%d", &op);
            if(op == 1)
            {
                scanf("%d", &x);
                Update(x);
            }
            else
            {
                RD(l), RD(r), RD(k);
                int len = r - l + 1;
                Node tot = Query(l, r);
                if(k > len - tot.mate * 2) puts("-1");
                else printf("%d\n", find(l, r, l, r, k));
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值