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

题目链接

题目大意

  三种操作,破坏一个点,修复最后被破坏的点,询问包含这个点的连续区间的最大长度。

解题思路

  用线段树维护父节点的前缀最长区间和后缀最长区间。
  父节点的前缀最长区间最小等于左二子的最长前缀区间,如果左儿子的最长前缀区间是整个区间,那么父节点的最长前缀区间则还可以加上右二子的最长前缀区间。父节点的后缀最长区间同理。
  对于询问,询问的位置可能有两种情况,一时pos<=区间中点mid,一是pos>mid。
  对于前者,如果从mid到pos是连续的,则包含mid的区间长度就是答案,也就是tree[rt<<1].post+tree[rt<<1|1].pre,否则继续缩小区间。
  对于后者,如果从mid+1到pos时连续的,那么答案也和上面一样。

代码

const int maxn = 1e5+10;
struct Tree {
    int l, r, len, pre, post;
} tree[maxn<<2];
int n, m;
inline void push_down(int rt) {
    tree[rt].pre = tree[rt<<1].pre;
    tree[rt].post = tree[rt<<1|1].post;
    if (tree[rt<<1].pre==tree[rt<<1].len) tree[rt].pre = tree[rt<<1].pre+tree[rt<<1|1].pre;
    if (tree[rt<<1|1].post==tree[rt<<1|1].len) tree[rt].post = tree[rt<<1|1].post+tree[rt<<1].post;
}
void build(int rt, int l, int r) {
    tree[rt].l = l, tree[rt].r = r, tree[rt].len = r-l+1;
    if (l==r) {
        tree[rt].pre = tree[rt].post = 1;
        return;
    }
    int mid = (l+r)>>1;
    build(rt<<1, l, mid);
    build(rt<<1|1, mid+1, r);
    push_down(rt);
}
void update(int rt, int pos, int val) {
    if (tree[rt].l==tree[rt].r) {
        tree[rt].post = tree[rt].pre = val;
        return;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if (mid>=pos) update(rt<<1, pos, val);
    else update(rt<<1|1, pos, val);
    push_down(rt);
}
int quary(int rt, int pos) {
    if (tree[rt].l==tree[rt].r) return tree[rt].pre; 
    //如果区间长度大于1,那么只有答案是0的时候会l=r,否则,可能是0,也可能是1
    //总之区间能缩小到l=r,那么这点被破坏就是0,否则就是1
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if (mid>=pos) {
        if (tree[rt<<1].post+pos>mid) return tree[rt<<1].post+tree[rt<<1|1].pre; 
        //区间中点所在的区间左边能否包含pos
        else return quary(rt<<1, pos);
    }
    else {
        if (tree[rt<<1|1].pre+mid>=pos) return tree[rt<<1].post+tree[rt<<1|1].pre;
        //区间中点+1所在的区间右边能否包含pos
        else return quary(rt<<1|1, pos);
    }
}
int main() {
    while(cin >> n >> m) {
        stack<int> sk;
        build(1, 1, n);
        for (int i = 1; i<=m; ++i) {
            char ch[5]; scanf("%s", ch);
            if (ch[0]=='D') {
                int num; scanf("%d", &num);
                update(1, num, 0); sk.push(num);
            }
            else if (ch[0]=='Q') {
                int num; scanf("%d", &num);
                printf("%d\n", quary(1, num)); 
            }
            else if (!sk.empty()) update(1, sk.top(), 1), sk.pop();
        }
    }
    return 0;
}
posted @ 2020-10-17 21:27  shuitiangong  阅读(121)  评论(0编辑  收藏  举报