HDU 1540 Tunnel Warfare(线段树区间合并)

题意:

题目定义了3种操作
D代表破坏村庄,
R代表修复最后被破坏的那个村庄,
Q代表询问包括x在内的最大连续区间是多少

思路:

和前面几道线段树的区间合并一样,在线段树的区间内,我们要用三个变量记录左边连续区间,右边连续区间和最大连续区间。
这题主要的难点是怎么查询。
我的查询函数是这么写的。

int query(int o, int L, int R, int pos) {
    if(L == R) return 0;
    int M = MID;
    pushDown(o, L, R);
    if(M - mxR[ls] + 1 <= pos && pos <= M + mxL[rs])
        return mxR[ls] + mxL[rs]; 
    else if(pos <= M) return query(lson, pos);
    else return query(rson, pos);
}

判断当前的位置是否满足在左边连续和右边连续的区间之内。
如果满足返回当前该区间的长度,否则向下查找。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define MID (L + R) >> 1
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
#define LEN(L, R) ((R) - (L) + 1)
using namespace std;
const int N = (int)5e4 + 10;

int n, m;
int mxL[N<<2], mxR[N<<2], mx[N<<2], cov[N<<2];
vector<int> vec;

int max(int a, int b, int c) {
    return max(a, max(b, c));
}

void pushUp(int o, int L, int R) {
    int M = MID;
    mxL[o] = mxL[ls], mxR[o] = mxR[rs];
    mx[o] = max(mx[ls], mx[rs], mxR[ls] + mxL[rs]);

    if(mxL[ls] == LEN(L, M)) mxL[o] += mxL[rs];
    if(mxR[rs] == LEN(M+1, R)) mxR[o] += mxR[ls];

    if(cov[ls] == cov[rs]) cov[o] = cov[ls];
    else cov[o] = -1;
}

void pushDown(int o, int L, int R) {
    if(cov[o] != -1) {
        int M = MID;
        cov[ls] = cov[rs] = cov[o];
        mxL[ls] = mxR[ls] = mx[ls] = cov[o] * LEN(L, M);
        mxL[rs] = mxR[rs] = mx[rs] = cov[o] * LEN(M+1, R);
        cov[o] = -1;
    }
}

void build(int o, int L, int R) {
    cov[o] = -1;
    if(L == R) {
        mxL[o] = mxR[o] = mx[o] = cov[o] = 1;
        return ;
    }
    int M = MID;
    build(lson);
    build(rson);
    pushUp(o, L, R);
}

void modify(int o, int L, int R, int pos, int val) {
    if(L == R) {
        mxL[o] = mxR[o] = mx[o] = cov[o] = val;
        return ;
    }
    int M = MID;
    pushDown(o, L, R);
    if(pos <= M) modify(lson, pos, val);
    else modify(rson, pos, val);
    pushUp(o, L, R);
}

int query(int o, int L, int R, int pos) {
    if(L == R) return 0;
    int M = MID;
    pushDown(o, L, R);
    if(M - mxR[ls] + 1 <= pos && pos <= M + mxL[rs])
        return mxR[ls] + mxL[rs]; 
    else if(pos <= M) return query(lson, pos);
    else return query(rson, pos);
}

int main() {
    char op[10];
    int ql, qr, x;
    while(~scanf("%d%d", &n, &m)) {
        build(1, 1, n);
        vec.clear();
        while(m--) {
            scanf("%s", op);
            if(op[0] == 'D') {
                scanf("%d", &x);
                vec.push_back(x);
                modify(1, 1, n, x, 0);
            }else if(op[0] == 'Q') {
                scanf("%d", &x);
                int ans = query(1, 1, n, x);
                printf("%d\n", ans);
            }else if(op[0] == 'R') {
                x = vec.back();
                vec.pop_back();
                modify(1, 1, n, x, 1);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值