题目链接: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;
}