zoukankan      html  css  js  c++  java
  • 一本通1558聚会

    1558:聚会

    题目描述

    原题来自:AHOI 2008

    Y 岛风景美丽宜人,气候温和,物产丰富。Y 岛上有 NN 个城市,有 N-1 条城市间的道路连接着它们。每一条道路都连接某两个城市。幸运的是,小可可通过这些道路可以走遍 Y 岛的所有城市。神奇的是,乘车经过每条道路所需要的费用都是一样的。

    小可可,小卡卡和小 YY 经常想聚会,每次聚会,他们都会选择一个城市,使得三个人到达这个城市的总费用最小。

    由于他们计划中还会有很多次聚会,每次都选择一个地点是很烦人的事情,所以他们决定把这件事情交给你来完成。他们会提供给你地图以及若干次聚会前他们所处的位置,希望你为他们的每一次聚会选择一个合适的地点。

    输入格式

    第一行两个正整数,N 和 M。分别表示城市个数和聚会次数;

    后面有 N1 行,每行用两个正整数 A 和 B 表示编号为 A 和编号为 B 的城市之间有一条路。城市的编号是从 1 到 N 的;

    再后面有 M 行,每行用三个正整数表示一次聚会的情况:小可可所在的城市编号,小卡卡所在的城市编号以及小 YY 所在的城市编号。

    输出格式

    一共有 M 行,每行两个数 P 和 C,用一个空格隔开。表示第 i 次聚会的地点选择在编号为 P 的城市,总共的费用是经过 C 条道路所花费的费用。

    样例

    样例输入

    6 4
    1 2
    2 3
    2 4
    4 5
    5 6
    4 5 6
    6 3 1
    2 4 4
    6 6 6

    样例输出

    5 2
    2 5
    4 1
    6 0

    数据范围与提示

    40% 的数据中,1N,M2×10^3;

    100% 的数据中,1N,M5×10^5。

    sol:只要无耻的抄结论就可以了:

    求三个结点到一个结点距离之和最小的结点以及距离和

    求出两两lca,其中有两个相同,答案则为另一个,画画图就可以理解

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100005,M=200005;
    int n,m;
    struct Tree
    {
        int tot,Next[M],to[M],head[N];
        inline void add(int x,int y)
        {
            Next[++tot]=head[x];
            to[tot]=y;
            head[x]=tot;
            return;
        }
        int F[N][23],Depth[N];
        inline void dfs(int x,int fa)
        {
            F[x][0]=fa;
            Depth[x]=Depth[fa]+1;
            int i;
            for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
            {
                dfs(to[i],x);
            }
            return;
        }
        inline void Pre()
        {
            int i,j;
            dfs(1,1);
            for(i=1;i<=19;i++)
            {
                for(j=1;j<=n;j++) F[j][i]=F[F[j][i-1]][i-1];
            }
            return;
        }
        inline int Ask_Lca(int x,int y)
        {
            int i;
            if(Depth[x]<Depth[y]) swap(x,y);
            for(i=19;~i;i--) if(Depth[F[x][i]]>=Depth[y])
            {
                x=F[x][i];
            }
            if(x==y) return x;
            for(i=19;~i;i--) if(F[x][i]!=F[y][i])
            {
                x=F[x][i]; y=F[y][i];
            }
            return F[x][0];
        }
        inline void Solve(int a,int b,int c)
        {
            int ab=Ask_Lca(a,b),ac=Ask_Lca(a,c),bc=Ask_Lca(b,c),pp;
            if(ab==ac) pp=bc;
            else if(ab==bc) pp=ac;
            else pp=ab;
            printf("%d %d
    ",pp,Depth[a]+Depth[b]+Depth[c]-Depth[ab]-Depth[ac]-Depth[bc]);
            return;
        }
    }T;
    int main()
    {
        int i;
        scanf("%d%d",&n,&m);
        for(i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            T.add(x,y);
            T.add(y,x);
        }
        T.Pre();
        for(i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            T.Solve(a,b,c);
        }
        return 0;
    }
    /*
    input
    6 4
    1 2
    2 3
    2 4
    4 5
    5 6
    4 5 6
    6 3 1
    2 4 4
    6 6 6
    output
    5 2
    2 5
    4 1
    6 0
    */
    View Code
  • 相关阅读:
    Python字符串
    MySQL触发器
    MySQL 1418报错解决办法
    数据库下载
    补码与反码
    二、八、十六进制之间的转换
    this 指向
    作用域 var 词法分析 arguments
    事件绑定的3种方式
    清浮动方法小结
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10353059.html
Copyright © 2011-2022 走看看