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;

}

 

你可能感兴趣的:(pku)