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;
}

 

posted on 2012-08-24 20:24  getgoing  阅读(247)  评论(0编辑  收藏  举报

导航