6580: 聚会 倍增LCA

发布时间 2023-10-15 16:15:24作者: CRt0729

描述

 

 

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

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

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

 

 

输入

 

 

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

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

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

40% 的数据中,1≤N,M≤2×103 ;

100% 的数据中,1≤N,M≤5×105

 

 

输出

 

 

一共有 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

原理:三个结点的最近公共祖先里必有两个是相同的,而最近的点就是第三个祖先,所以求出第三个祖先后再计算三个节点到这个祖先的距离就是答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+10,inf = 0x3f3f3f3f;
struct node{
    int to,nex;
};
node e[N * 2];
int head[N * 2],cnt;
int f[N][21],dis[N],dep[N];
int n,m,x,y,z;
void add(int x,int y)
{
    e[++cnt].to = y;
    e[cnt].nex = head[x];
    head[x] = cnt;
}
void dfs(int x,int fa)
{
    dep[x] = dep[fa] + 1;
    for(int i = 1; i <= 20; i++)
        f[x][i] = f[f[x][i - 1]][i - 1];
    for(int i = head[x]; i; i = e[i].nex)
    {
        int y = e[i].to;
        if(y == fa)continue;
        f[y][0] = x;
        dfs(y,x);
    }
}
int lca(int x,int y)
{
    if(dep[x] < dep[y])swap(x,y);
    for(int i = 20; i >= 0; i--)
    {
        if(dep[f[x][i]] >= dep[y]) x = f[x][i];
        if(x == y) return x;
    }
    for(int i = 20; i >= 0; i--)
    {
        if(f[x][i] != f[y][i])
        {
            x = f[x][i],y = f[y][i];
        }
    }
    return f[x][0];
}
int main()
{
    cin >> n >> m;
    for(int i = 1; i < n; i++)
    {
        scanf("%d %d",&x,&y);
        add(x,y);add(y,x);
    }
    dfs(1,0);
    while(m--)
    {
        scanf("%d %d %d",&x,&y,&z);
        int t1 = lca(x,y),t2 = lca(x,z),t3 = lca(y,z);
        int pos;
        if(t1 == t2) pos = t3;
        else if(t1 == t3) pos = t2;
        else pos = t1;
        int ans = dep[x] + dep[y] + dep[z] - dep[t1] - dep[t2] - dep[t3];
        printf("%d %d\n",pos,ans);
    }
    return 0;
}