PKU 2892 Tunnel Warfare
维护某个位置 i 左右可以到达的最大长度lx, ly,那么询问的输出为lx+ly-1(当然,如果 i 已经被标记(炸毁且尚未修复)输出0,这种情况加个判断);
容易发现:
每次删除一个点时,这个点左边可以到达的所有点可以向右到达的最大长度要减去 ly,同理这个点右边的点可以到达左边的最大长度要减去 lx;
当修复一个点时,可以先询问它左(右)边的那个点的最大连通长度 lx(ly),那么可以对它前面 lx 个点向右可以到达的长度加上 ly+1,同理对它后面 ly 个点向左可以到达的最大长度加上 lx+1(两种操作都包含当前这个点),这样就相当于完成了修复;
由于每次修复的是最近一次删除的点,可以用栈来保存,数据似乎不含未修复情况下炸毁一个点的情况,我考虑了这一点。
1Y,很好。
# include <stdio.h> # include <string.h> # define N 50005 # define ls ((r)<<1) # define rs ((r)<<1|1) # define mid (((x)+(y))>>1) int n, m; char b[N]; int lx[N<<2], rx[N<<2], st[N], top; void build(int r, int x, int y) { lx[r] = rx[r] = 0; if (x == y) { lx[r] = x, rx [r] = n-x+1; return ; } build(ls, x, mid); build(rs, mid+1, y); } void pushdown(int r, int x, int y, int *v) { if (v[r]) { v[ls] += v[r]; v[rs] += v[r]; v[r] = 0; } } int query(int r, int x, int y, int k, int *v) { if (x == y) return v[r]; pushdown(r, x, y, v); if (k <= mid) return query(ls, x, mid, k, v); else return query(rs, mid+1, y, k, v); } void add(int r, int x, int y, int *v, int s, int t, int val) { if (s<=x && y<=t) { v[r] += val; return ; } pushdown(r, x, y, v); if (s <= mid) add(ls, x, mid, v, s, t, val); if (mid+1<=t) add(rs, mid+1, y, v, s, t, val); } void solve(void) { int i, x, s, t, dl, dr; char op[3]; top = 0; memset(b+1, 0, sizeof(b[0])*n); scanf("%d%d", &n, &m); build(1, 1, n); for (i = 1; i <= m; ++i) { scanf("%s", op); switch(op[0]) { case 'D': { scanf("%d", &x), st[top++] = x, b[x] = 1; dl = query(1, 1, n, x, lx); dr = query(1, 1, n, x, rx); s = x+1-dl, t = x-1+dr; //printf("%c\t%d\t%d %d\t%d %d\n", op[0], x, s, t, -dr, -dl); if (t < s) ; else { add(1, 1, n, lx, x, t, -dl); add(1, 1, n, rx, s, x, -dr); } break; } case 'Q': { scanf("%d", &x); if (b[x]) printf("%d\n", 0); else { dl = query(1, 1, n, x, lx); dr = query(1, 1, n, x, rx); //printf("%c\t%d\t%d %d\n", op[0], x, dl, dr); printf("%d\n", dl+dr-1); } break; } case 'R': { x = st[--top]; if (b[x] == 0) break; b[x] = 0; if (x == 1) dl = 0; else dl = query(1, 1, n, x-1, lx); if (x == n) dr = 0; else dr = query(1, 1, n, x+1, rx); //printf("%c\t%d\t%d %d\n", op[0], x, x+dr, x-dl); add(1, 1, n, lx, x, x+dr, dl+1); add(1, 1, n, rx, x-dl, x, dr+1); break; } } } } int main() { //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); solve(); return 0; }