bzoj2325 [ZJOI2011]道馆之战

2325: [ZJOI2011]道馆之战

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 1340  Solved: 501
[Submit][Status][Discuss]

Description

口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中
的每一个冰块都只能经过一次。当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开。三个冰
地分别如下:
当走出第三个冰地之后,就可以与馆主进行道馆战了。馆主发现这个难度太小,导致经常有挑战者能通过,为了加
大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地。任意两个房间之间均有且仅有一
条路径相连,即这n个房间构成一个树状结构。每个房间分成了A和B两个区域,每一区域都是一个薄冰块或者障碍
物。每次只能移动到相邻房间的同一类区域(即若你现在在这个房间的A区域,那么你只能移动到相邻房间的A区域)
或这个房间的另一区域。现在挑战者从房间u出发,馆主在房间v,那么挑战者只能朝接近馆主所在房间的方向过去
。一开始挑战者可以在房间u的任意一个冰块区域内。如果挑战者踩过的冰块数达到了最大值(即没有一种方案踩过
的冰块数更多了),那么当挑战者走到最后一个冰块上时,他会被瞬间传送到馆主面前与馆主进行道馆战。自从馆
主修改规则后已经经过了m天,每天要么是有一个挑战者来进行挑战,要么就是馆主将某个房间进行了修改。对于
每个来的挑战者,你需要计算出他若要和馆主进行战斗需要经过的冰块数。

Input

第一行包含两个正整数n和m。第2行到第n行,每行包含两个正整数x和y,表示一条连接房间x和房间y的边。房间编
号为1…n。接下来n行,每行包含两个字符。第n + k行表示房间k的两个区域,第一个字符为A区域,第二个字符为
B区域。其中“.”(ASCII码为46)表示是薄冰块,“#”(ASCII码为35)表示是障碍物。最后的m行,每行一个操作:
l C u s:将房间u里的两个区域修改为s。
l Q u v:询问挑战者在房间u,馆主在房间v时,挑战者能与馆主进行挑战需要踩的冰块数。如果房间u的两个区域
都是障碍物,那么输出0。
N≤ 30 000
M ≤ 80 000

Output

包含若干行,每行一个整数。即对于输入中的每个询问,依次输出一个答案。

Sample Input

5 3
1 2
2 3
2 4
1 5
.#
..
#.
.#
..
Q 5 3
C 1 ##
Q 4 5

Sample Output

6
3
分析:这道题和bzoj1018很像啊,做法都是差不多的.
   考虑在链上的情况,在当前考虑的区间中,令dis[0][0]表示从左上走到右上的最长路,dis[0][1]表示从左上到右下,dis[1][0],dis[1][1]以此类推. 令maxx[0][0]表示从左上出发能走的最大距离,maxx[0][1]表示左下的,maxx[1][0]表示右上,maxx[1][1]表示右下.它们的合并比较简单,没有了bzoj1018可以绕一圈的情况.令当前区间为c,左半区间为a,右半区间为b,那么:

c.dis[0][0] = max(-inf,max(a.dis[0][0] + b.dis[0][0],a.dis[0][1] + b.dis[1][0]));
c.dis[1][1] = max(-inf,max(a.dis[1][1] + b.dis[1][1],a.dis[1][0] + b.dis[0][1]));
c.dis[0][1] = max(-inf,max(a.dis[0][0] + b.dis[0][1],a.dis[0][1] + b.dis[1][1]));
c.dis[1][0] = max(-inf,max(a.dis[1][1] + b.dis[1][0],a.dis[1][0] + b.dis[0][0]));
c.maxx[0][0] = max(a.maxx[0][0],max(a.dis[0][0] + b.maxx[0][0],a.dis[0][1] + b.maxx[0][1]));
c.maxx[0][1] = max(a.maxx[0][1],max(a.dis[1][0] + b.maxx[0][0],a.dis[1][1] + b.maxx[0][1]));
c.maxx[1][0] = max(b.maxx[1][0],max(b.dis[0][0] + a.maxx[1][0],b.dis[1][0] + a.maxx[1][1]));
c.maxx[1][1] = max(b.maxx[1][1],max(b.dis[0][1] + a.maxx[1][0],b.dis[1][1] + a.maxx[1][1]));

   在树上怎么办呢?每次询问的是两个点之间的路径,很显然,要用线段树+树链剖分. 如果询问的两个点分别是x,y,令lans表示x向上跳得到的答案,rans表示y向上跳得到的答案,最后要将lans取反再与rans合并,因为当两个点最后跳到一起时,它们的左端点对应左端点,右端点对应右端点,而我们要求左端点对应右端点,右端点对应左端点,所以要取反:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 30010,inf = (1 << 30);
int n,m,head[maxn],to[maxn * 2],nextt[maxn * 2],tot = 1,sizee[maxn],son[maxn],top[maxn];
int pos[maxn],id[maxn],dfs_clock,fa[maxn],a[maxn][2],deep[maxn];

struct node
{
    int dis[2][2],maxx[2][2];
    void clear()
    {
        memset(dis,0,sizeof(dis));
        memset(maxx,0,sizeof(maxx));
    }
    bool emptyy()
    {
        if (!dis[0][0] && !dis[0][1] && !dis[1][0] && !dis[1][1] && !maxx[0][0] && !maxx[0][1] && !maxx[1][0] && !maxx[1][1])
            return true;
        return false;
    }
}e[maxn << 2];

void add(int x,int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void dfs1(int u,int faa)
{
    fa[u] = faa;
    sizee[u] = 1;
    deep[u] = deep[faa] + 1;
    for (int i = head[u]; i; i = nextt[i])
    {
        int v = to[i];
        if (v == faa)
            continue;
        dfs1(v,u);
        sizee[u] += sizee[v];
        if (sizee[v] > sizee[son[u]])
            son[u] = v;
    }
}

void dfs2(int u,int topp)
{
    top[u] = topp;
    pos[u] = ++dfs_clock;
    id[dfs_clock] = u;
    if (son[u])
        dfs2(son[u],topp);
    for (int i = head[u]; i; i = nextt[i])
    {
        int v = to[i];
        if (v == fa[u] || v == son[u])
            continue;
        dfs2(v,v);
    }
}

node pushup(node a,node b)
{
    node c;
    if (a.emptyy())
        c = b;
    else if (b.emptyy())
        c = a;
    else
    {
        c.dis[0][0] = max(-inf,max(a.dis[0][0] + b.dis[0][0],a.dis[0][1] + b.dis[1][0]));
        c.dis[1][1] = max(-inf,max(a.dis[1][1] + b.dis[1][1],a.dis[1][0] + b.dis[0][1]));
        c.dis[0][1] = max(-inf,max(a.dis[0][0] + b.dis[0][1],a.dis[0][1] + b.dis[1][1]));
        c.dis[1][0] = max(-inf,max(a.dis[1][1] + b.dis[1][0],a.dis[1][0] + b.dis[0][0]));
        c.maxx[0][0] = max(a.maxx[0][0],max(a.dis[0][0] + b.maxx[0][0],a.dis[0][1] + b.maxx[0][1]));
        c.maxx[0][1] = max(a.maxx[0][1],max(a.dis[1][0] + b.maxx[0][0],a.dis[1][1] + b.maxx[0][1]));
        c.maxx[1][0] = max(b.maxx[1][0],max(b.dis[0][0] + a.maxx[1][0],b.dis[1][0] + a.maxx[1][1]));
        c.maxx[1][1] = max(b.maxx[1][1],max(b.dis[0][1] + a.maxx[1][0],b.dis[1][1] + a.maxx[1][1]));
    }
    return c;
}

void build(int o,int l,int r)
{
    if (l == r)
    {
        int p = a[id[l]][0],q = a[id[l]][1];
        if (p == 1 && q == 1)
        {
            e[o].dis[0][0] = e[o].dis[1][1] = 1;
            e[o].dis[0][1] = e[o].dis[1][0] = 2;
            e[o].maxx[0][0] = e[o].maxx[0][1] = e[o].maxx[1][0] = e[o].maxx[1][1] = 2;
        }
        else if (p == 1)
        {
            e[o].dis[0][0] = 1;
            e[o].dis[0][1] = e[o].dis[1][0] = e[o].dis[1][1] = -inf;
            e[o].maxx[0][0] = e[o].maxx[1][0] = 1;
            e[o].maxx[0][1] = e[o].maxx[1][1] = -inf;
        }
        else if (q == 1)
        {
            e[o].dis[0][0] = e[o].dis[0][1] = e[o].dis[1][0] = -inf;
            e[o].dis[1][1] = 1;
            e[o].maxx[0][0] = e[o].maxx[1][0] = -inf;;
            e[o].maxx[0][1] = e[o].maxx[1][1] = 1;
        }
        else
        {
            for (int i = 0; i <= 1; i++)
                for (int j = 0; j <= 1; j++)
                    e[o].dis[i][j] = e[o].maxx[i][j] = -inf;
        }
        return;
    }
    int mid = (l + r) >> 1;
    build(o * 2,l,mid);
    build(o * 2 + 1,mid + 1,r);
    e[o] = pushup(e[o * 2],e[o * 2 + 1]);
}

void update(int o,int l,int r,int v,int p,int q)
{
    if (l == r)
    {
        if (p == 1 && q == 1)
        {
            e[o].dis[0][0] = e[o].dis[1][1] = 1;
            e[o].dis[0][1] = e[o].dis[1][0] = 2;
            e[o].maxx[0][0] = e[o].maxx[0][1] = e[o].maxx[1][0] = e[o].maxx[1][1] = 2;
        }
        else if (p == 1)
        {
            e[o].dis[0][0] = 1;
            e[o].dis[0][1] = e[o].dis[1][0] = e[o].dis[1][1] = -inf;
            e[o].maxx[0][0] = e[o].maxx[1][0] = 1;
            e[o].maxx[0][1] = e[o].maxx[1][1] = -inf;
        }
        else if (q == 1)
        {
            e[o].dis[0][0] = e[o].dis[0][1] = e[o].dis[1][0] = -inf;
            e[o].dis[1][1] = 1;
            e[o].maxx[0][0] = e[o].maxx[1][0] = -inf;;
            e[o].maxx[0][1] = e[o].maxx[1][1] = 1;
        }
        else
        {
            for (int i = 0; i <= 1; i++)
                for (int j = 0; j <= 1; j++)
                    e[o].dis[i][j] = e[o].maxx[i][j] = -inf;
        }
        return;
    }
    int mid = (l + r) >> 1;
    if (v <= mid)
        update(o * 2,l,mid,v,p,q);
    else
        update(o * 2 + 1,mid + 1,r,v,p,q);
    e[o] = pushup(e[o * 2],e[o * 2 + 1]);
}

node fan(node a)
{
    swap(a.maxx[0][0],a.maxx[1][0]);
    swap(a.maxx[0][1],a.maxx[1][1]);
    swap(a.dis[0][1],a.dis[1][0]);
    return a;
}

node query(int o,int l,int r,int x,int y)
{
    if (l == x && r == y)
        return e[o];
    int mid = (l + r) >> 1;
    if (y <= mid)
        return query(o * 2,l,mid,x,y);
    else
        if (x > mid)
            return query(o * 2 + 1,mid + 1,r,x,y);
    else
        return pushup(query(o * 2,l,mid,x,mid),query(o * 2 + 1,mid + 1,r,mid + 1,y));
}

int Query(int x,int y)
{
    node lans,rans;
    lans.clear();
    rans.clear();
    while (top[x] != top[y])
    {
        if (deep[top[x]] < deep[top[y]])
        {
            rans = pushup(query(1,1,n,pos[top[y]],pos[y]),rans);
            y = fa[top[y]];
        }
        else
        {
            lans = pushup(query(1,1,n,pos[top[x]],pos[x]),lans);
            x = fa[top[x]];
        }
    }
    if (deep[x] > deep[y])
        lans = pushup(query(1,1,n,pos[y],pos[x]),lans);
    else
        rans = pushup(query(1,1,n,pos[x],pos[y]),rans);
    lans = pushup(fan(lans),rans);
    int temp = max(lans.maxx[0][0],lans.maxx[0][1]);
    if (temp < 0)
        temp = 0;
    return temp;
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i < n; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    for (int i = 1; i <= n; i++)
    {
        char ch[3];
        scanf("%s",ch);
        if (ch[0] == '.')
            a[i][0] = 1;
        else
            a[i][0] = 0;
        if (ch[1] == '.')
            a[i][1] = 1;
        else
            a[i][1] = 0;
    }
    build(1,1,n);
    while (m--)
    {
        char ch[2],s[3];
        scanf("%s",ch);
        int u,v,p,q;
        if (ch[0] == 'C')
        {
            scanf("%d",&u);
            scanf("%s",s);
            if (s[0] == '.')
                p = 1;
            else
                p = 0;
            if (s[1] == '.')
                q = 1;
            else
                q = 0;
            update(1,1,n,pos[u],p,q);
        }
        else
        {
            scanf("%d%d",&u,&v);
            printf("%d\n",Query(u,v));
        }
    }

    return 0;
}

 

 

posted @ 2018-03-04 15:06  zbtrs  阅读(405)  评论(0编辑  收藏  举报