洛谷P1503 鬼子进村 题解 线段树+二分

题目链接:https://www.luogu.com.cn/problem/P1503

解题思路:

用线段树维护区间和,一开始所有的位置对应的值为 \(1\),如果有一个房间被摧毁,更新为 \(0\);被修复,更新为 \(1\)

查询以 \(x\) 结尾和开头的最长连续 \(1\),可以用二分+线段树求区间和。

实现复杂度 \(O(n \cdot log n \cdot log n)\)

实现代码如下:

#include 
using namespace std;
const int maxn = 50050;
int tree[maxn<<2];
void push_up(int rt) {
    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void update(int p, int x, int l, int r, int rt) {
    if (l == r) tree[rt] = x;
    else {
        int mid = (l + r) / 2;
        if (p <= mid) update(p, x, lson);
        else update(p, x, rson);
        push_up(rt);
    }
}
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return tree[rt];
    int mid = (l + r) / 2, ans = 0;
    if (L <= mid) ans += query(L, R, lson);
    if (R > mid) ans += query(L, R, rson);
    return ans;
}
void build(int l, int r, int rt) {
    if (l == r) {
        tree[rt] = 1;
        return;
    }
    int mid = (l + r) / 2;
    build(lson);
    build(rson);
    push_up(rt);
}
stack stk;
int n, m, x;
char ch[2];
int main() {
    scanf("%d%d", &n, &m);
    build(1, n, 1);
    while (m --) {
        scanf("%s", ch);
        if (ch[0] == 'D') {
            scanf("%d", &x);
            update(x, 0, 1, n, 1);
            stk.push(x);
        }
        else if (ch[0] == 'R') {
            if (!stk.empty()) {
                x = stk.top();
                stk.pop();
                update(x, 1, 1, n, 1);
            }
        }
        else {
            scanf("%d", &x);
            if (query(x, x, 1, n, 1) == 0) {
                puts("0");
                continue;
            }
            int L, R, res1 = x, res2 = x;
            L = 1, R = x;
            while (L <= R) {
                int mid = (L + R) / 2;
                if (query(mid, x, 1, n, 1) == x-mid+1) {
                    res1 = mid;
                    R = mid-1;
                }
                else L = mid+1;
            }
            L = x, R = n;
            while (L <= R) {
                int mid = (L + R) / 2;
                if (query(x, mid, 1, n, 1) == mid-x+1) {
                    res2 = mid;
                    L = mid+1;
                }
                else R = mid-1;
            }
            printf("%d\n", res2 - res1 + 1);
        }
    }
    return 0;
}

你可能感兴趣的:(洛谷P1503 鬼子进村 题解 线段树+二分)