Tunnel Warfare(线段树取连续区间)

 

emmmmmmmm我菜爆了

思路来自:https://blog.csdn.net/chudongfang2015/article/details/52133243

线段树最难的应该就是要维护什么东西

这道题刚开始1~n都是连通的

D x 即破坏x这个地方

Q x 即查询包含x的连续区间有多长

R 即修复最后一次D的x

博主给了一个非常好的思路

线段树维护两个值,该区间内被破坏的最大的点,以及最小的那个点

如 1,2,...,,6 破坏了 2 ,4,5 那么该区间里的pmax = 5,pmin = 2

若要查询3 则取3右边的pmin 减去 3左边的pmax 再减1

3右的pmin = 4, 3左的pmax = 2 即为 4 - 2 - 1 = 1

未被破坏的点或者区间的pmax pmin分别设为0,n + 1

这样就能query的值能直接用来计算

比如1,2,3,4,5均为被破坏

则pmin - pmax - 1 = n = 5

特殊情况就为查询的x自身被破坏了

pmin = pmax = x 这样打印的结果是-1,所以打印的时候取一下pmin-pmax-1和0的最大值就好了

(orz多转换思路,试试各种值的维护)

#include <cstdio>
#include <algorithm>
#define lp p<<1
#define rp p<<1|1
using namespace std;
const int maxn = 5e4 + 10;
int pmin[maxn<<2], pmax[maxn<<2];
int des[maxn], n;

void build(int p, int l, int r) {
    if (l == r) {
        pmin[p] = n + 1;
        pmax[p] = 0;
        return;
    }
    int mid = l + r >> 1;
    build(lp, l, mid);
    build(rp, mid + 1, r);
    pmax[p] = max(pmax[lp], pmax[rp]);
    pmin[p] = min(pmin[lp], pmin[rp]);
}
void update(int p, int l, int r, int pos, int num1, int num2) {
    if (l == r) {
        pmax[p] = num1;
        pmin[p] = num2;
        return;
    }
    int mid = l + r >> 1;
    if (pos <= mid) {
        update(lp, l, mid, pos, num1, num2);
    } else {
        update(rp, mid + 1, r, pos, num1, num2);
    }
    pmax[p] = max(pmax[lp], pmax[rp]);
    pmin[p] = min(pmin[lp], pmin[rp]);
}
int query_min(int p, int l, int r, int x, int y) {
    if (x <= l && y >= r) return pmin[p];
    int mid = l + r >> 1;
    int res = 0x3f3f3f3f;
    if (x <= mid) res = min(res, query_min(lp, l, mid, x, y));
    if (y > mid) res = min(res, query_min(rp, mid + 1, r, x, y));
    return res;
}
int query_max(int p, int l, int r, int x, int y) {
    if (x <= l && y >= r) return pmax[p];
    int mid = l + r >> 1;
    int res = 0;
    if (x <= mid) res = max(res, query_max(lp, l, mid, x, y));
    if (y > mid) res = max(res, query_max(rp, mid + 1, r, x, y));
    return res;
}

int main() {
    int m;
    while (~scanf("%d%d", &n, &m)) {
        int last = 0;
        build(1, 1, n);
        while (m--) {
            char opt[10];
            scanf("%s", opt);
            if (opt[0] == 'D') {
                int p;
                scanf("%d", &p);
                update(1, 1, n, p, p, p);
                des[++last] = p;
            } else if (opt[0] == 'R') {
                update(1, 1, n, des[last--], 0, n + 1);
            } else {
                int q;
                scanf("%d", &q);
                int ans1 = query_max(1, 1, n, 1, q), ans2 = query_min(1, 1, n, q, n);
                printf("%d\n", ans2 - ans1 - 1 > 0 ? ans2 - ans1 - 1 : 0);
            }
        }
    }
    return 0;
}
View Code

对博主的代码简化了一下下(

posted @ 2019-03-03 11:07  Mrzdtz220  阅读(393)  评论(0)    收藏  举报