题意:一条线上的点,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;
}