题目链接
题意:n个村庄连成一排,有3种操作
D x 破坏x村庄
R 恢复上一个被破坏的村庄
Q x 询问x村庄所在连续村庄长度
思路:线段树的区间合并,记录区间左边,右边连续,和区间最大连续,由于都是单点操作所以没必要延时了,然后对于恢复操作可以用一个栈记录下之前的操作即可
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define lson(x) ((x<<1)+1) #define rson(x) ((x<<1)+2) const int N = 50005; int n, m; struct Node { int l, r, lsum, rsum, sum; int size() {return r - l + 1;} } node[N * 4]; int st[N], top; void pushup(int x) { node[x].lsum = node[lson(x)].lsum; node[x].rsum = node[rson(x)].rsum; node[x].sum = max(node[lson(x)].sum, node[rson(x)].sum); if (node[lson(x)].lsum == node[lson(x)].size()) node[x].lsum += node[rson(x)].lsum; if (node[rson(x)].rsum == node[rson(x)].size()) node[x].rsum += node[lson(x)].rsum; node[x].sum = max(node[x].sum, node[lson(x)].rsum + node[rson(x)].lsum); } void build(int l, int r, int x = 0) { node[x].l = l; node[x].r = r; if (l == r) { node[x].lsum = node[x].rsum = node[x].sum = 1; return; } int mid = (l + r) / 2; build(l, mid, lson(x)); build(mid + 1, r, rson(x)); pushup(x); } void add(int v, int val, int x = 0) { if (node[x].l == node[x].r) { node[x].lsum = node[x].rsum = node[x].sum = val; return; } int mid = (node[x].l + node[x].r) / 2; if (v <= mid) add(v, val, lson(x)); if (v > mid) add(v, val, rson(x)); pushup(x); } int query(int v, int x = 0) { if (node[x].l == node[x].r) return node[x].sum; if (v < node[lson(x)].r - node[lson(x)].rsum + 1) return query(v, lson(x)); if (v > node[rson(x)].l + node[rson(x)].lsum - 1) return query(v, rson(x)); return node[lson(x)].rsum + node[rson(x)].lsum; } int main() { while (~scanf("%d%d", &n, &m)) { build(1, n); char op[2]; int v; top = 0; while (m--) { scanf("%s", op); if (op[0] == 'R') add(st[top--], 1); else { scanf("%d", &v); if (op[0] == 'D') { add(v, 0); st[++top] = v; } else printf("%d\n", query(v)); } } } return 0; }