zoukankan      html  css  js  c++  java
  • 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
    ",Query(u,v));
            }
        }
    
        return 0;
    }
  • 相关阅读:
    异步nodejs代码的同步样子写法样例
    npm用法及离线安装方法
    javascript 事件相关使用总结01
    python wsgi PEP333 中文翻译
    android webview 播放 video经验总结
    javascript面向对象的写法03
    javascript面向对象的写法02
    Nginx在Windows下的基本介绍安装以及基本使用
    window7下 cmd命令行 Mysql导出表结构 + 表数据
    【一】Spark基础
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8504747.html
Copyright © 2011-2022 走看看