-
假设一棵树上要求两个点的到某个点的最短路径,那么可以知道两个点到其两者的LCA距离和一定是最短的。
-
不难得到,三个点两两相互的LCA点一定有一个是一样的,进而可以发现,如果三个点要去那两个一样的LCA的其中一个,会导致第三个点走重复的路程,这样就不能保证是最短的了。
-
如果要保证路程最短,那么也就是尽量要减少重复走的路程,可以发现,如果三点同时走那个唯一的LCA,则没有重复路程,这样距离之和就是最短的。
-
那么如何求最短的距离,对于两个点的距离来说,设两个点分别是a,b,那么其距离为depth[a] + depth[b] - 2 * dep[LCAab]对于这道题的三个点两两求一下就好了。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
const int M = 1e6 + 10;
int head[N], tot, n, m, fa[N][22], dep[N];
struct Edge{
int v, next;
}edge[M];
void add(int u, int v){
edge[tot].next = head[u];
edge[tot].v = v;
head[u] = tot ++;
}
void dfs(int now, int pre){
dep[now] = dep[pre] + 1;
fa[now][0] = pre;
for(int i = head[now]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(v != pre)
dfs(v, now);
}
}
int getlca(int u, int v){
if(dep[u] < dep[v])
swap(u, v);
while(dep[u] != dep[v])
u = fa[u][(int)log2(dep[u] - dep[v])];
if(u == v)
return u;
for(int i = 20; i >= 0; i --)
if(fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int main(){
scanf("%d%d", &n, &m);
memset(head, -1, sizeof head);
for(int i = 1; i < n; i ++){
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1, 0);
for(int j = 1; j <= 20; j ++)
for(int i = 1; i <= n; i ++)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
for(int i = 1; i <= m; i ++){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
int lca1 = getlca(a, b);
int lca2 = getlca(a, c);
int lca3 = getlca(b, c);
int unique = 0;
if(lca1 == lca2)
unique = lca3;
else if(lca1 == lca3)
unique = lca2;
else
unique = lca1;
int ans = dep[a] + dep[b] + dep[c] - dep[lca1] - dep[lca2] - dep[lca3];
printf("%d %d
", unique, ans);
}
return 0;
}