一本通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\n",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

 

posted @ 2019-02-05 20:24  yccdu  阅读(224)  评论(0编辑  收藏  举报