HDU1540Tunnel Warfare(线段树维护连续区间)

题意:一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。

思路:线段树维护连续区间,定义结构体来表示线段树节点,t[i].l,t[i].r表示这个节点所包含的区间从最左边起的最大连续区间,和从最右边起的最大连续区间

查询的时候我们考虑对于需要查询的点,往左右两个区间转移,如果在左子树且在右区间范围,那么结果就是左子树的右区间长度+右子树的左区间长度,如果在左子树但是不在其右区间范围内,那么查询左子树,如果在右子树同理可推

#include<bits/stdc++.h>
#define ll long long
#define MP make_pair
#define P pair<long long, long long>
using namespace std;
const int N = 1e5 + 10;
int n, m, k;
char op[4];
struct SGT {
    int s, l, r;
} t[N << 2];
void pushup(int rt, int len) {
    t[rt].l = t[rt << 1].l;
    t[rt].r = t[rt << 1 | 1].r;
    if(t[rt << 1].l == (len - (len >> 1)))
        t[rt].l = t[rt << 1].l + t[rt << 1 | 1].l;
    if(t[rt << 1 | 1].r == (len >> 1))
        t[rt].r = t[rt << 1].r + t[rt << 1 | 1].r;
    t[rt].s = max(t[rt << 1].r + t[rt << 1].l, max(t[rt << 1].s, t[rt << 1 | 1].s));
}
void build(int l, int r, int rt) {
    if(l == r) {
        t[rt] = SGT{1, 1, 1};
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    pushup(rt, r - l + 1);
}
void update(int l, int r, int rt, int c, int pos) {
    if(l == r) {
        t[rt] = SGT{c, c, c};
        return;
    }
    int mid = l + r >> 1;
    if(pos <= mid)
        update(l, mid, rt << 1, c, pos);
    else
        update(mid + 1, r, rt << 1 | 1, c, pos);
    pushup(rt, r - l + 1);
}
int query(int l, int r, int rt, int pos) {
    if(l == r)
        return t[rt].s;
    int mid = l + r >> 1;
    if(mid >= pos) {
        if(mid < pos + t[rt << 1].r)//在左子树且在右区间范围,那么结果就是左子树的右区间长度+右子树的左区间长度
            return t[rt << 1].r + t[rt << 1 | 1].l;
        return query(l, mid, rt << 1, pos);
    } else {
        if(mid + t[rt << 1 | 1].l >= pos)
            return t[rt << 1].r + t[rt << 1 | 1].l;
        return query(mid + 1, r, rt << 1 | 1, pos);
    }
}
int main() {
    while(~scanf("%d%d", &n, &m)) {
        build(1, n, 1);
        stack<int> q;
        while(m--) {
            scanf("%s", op);
            if(op[0] == 'D') {
                scanf("%d", &k);
                q.push(k);
                update(1, n, 1, 0, k);
            }
            if(op[0] == 'R')
                update(1, n, 1, 1, q.top()), q.pop();
            if(op[0] == 'Q') {
                scanf("%d", &k);
                printf("%d\n", query(1, n, 1, k));
            }
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值