- 题目大意
D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少,然后根据命令来进行模拟操作。
- 解题思路
这个我是根据线段树的区间合并的模板来写的,用三个变量记录左边连续区间,右边连续区间和最大连续区间,用栈来存储点(修复的时候要用),其余的就是更新点,然后查询最大的连续区间。
- 代码
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cstring> #include<stack> using namespace std; const int maxn = 50001; struct node { int l, r; int ls, rs, ms; }t[4 * maxn]; void build(int l, int r, int k) { int mid; t[k].l = l; t[k].r = r; t[k].ls = t[k].rs = t[k].ms = r - l + 1; if (l == r) return; mid = (l + r) / 2; build(l, mid, 2 * k); build(mid + 1, r, 2 * k + 1); } void add(int i, int r, int x) { int mid; if (t[i].r == t[i].l) { t[i].ls = t[i].rs = t[i].ms = x; return; } mid = (t[i].r + t[i].l) / 2; if (r <= mid) add(2 * i, r, x); else add(2 * i + 1, r, x); if (t[i * 2].ls == t[i * 2].r - t[i * 2].l + 1) t[i].ls = t[i * 2].ls + t[i * 2 + 1].ls; else t[i].ls = t[i * 2].ls; if (t[i * 2 + 1].rs == t[i * 2 + 1].r - t[i * 2 + 1].l + 1) t[i].rs = t[i * 2 + 1].rs + t[i * 2].rs; else t[i].rs = t[i * 2 + 1].rs; t[i].ms = max(max(t[i * 2].ms, t[i * 2 + 1].ms), t[i * 2].rs + t[i * 2 + 1].ls); } int findd(int k, int r) { int mid; if (t[k].l == t[k].r || t[k].ms == 0 || t[k].ms == t[k].r - t[k].l + 1) { return t[k].ms; } mid = (t[k].r + t[k].l) / 2; if (r <= mid) { if (r >= t[2 * k].r - t[2 * k].rs + 1) return t[k * 2].rs + t[k * 2 + 1].ls; else return findd(2 * k, r); } else { if (r <= t[2 * k + 1].l + t[2 * k + 1].ls - 1) return t[k * 2 + 1].ls + t[k * 2].rs; else return findd(2 * k + 1, r); } } int main() { int n, m, a; char str[10]; while(~scanf("%d%d", &n, &m)) { build(1, n, 1); stack<int>q; if(!q.empty()) q.pop(); while (m--) { scanf("%s", str); if (str[0] == 'D') { scanf("%d", &a); q.push(a); add(1, a, 0); } else if (str[0] == 'Q') { scanf("%d", &a); printf("%d ", findd(1, a)); } else if (str[0] == 'R') { a = q.top(); q.pop(); add(1, a, 1); } } } return 0; }