AHOI2008 聚会
先把每两个点之间的LCA求出来
画图模拟,显然可以(也可能并不显然)发现集合点选为深度最小的LCA时最优
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define mod 998244353
#define LL long long
using namespace std;
LL read() {
LL k = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
k = k * 10 + c - 48, c = getchar();
return k * f;
}
struct zzz {
int t, nex;
}e[500010 << 1]; int head[500010], tot;
void add(int x, int y) {
e[++tot].t = y;
e[tot].nex = head[x];
head[x] = tot;
}
int f[500010][32], lg[500010], deth[500010];
LL len[500010];
void dfs(int now, int fa) {
f[now][0] = fa; deth[now] = deth[fa] + 1;
len[now] = len[fa] + 1;
for(int i = 1; i <= lg[deth[now]]; ++i)
f[now][i] = f[f[now][i-1]][i-1];
for(int i = head[now]; i; i = e[i].nex)
if(e[i].t != fa) dfs(e[i].t, now);
}
int LCA(int x, int y) {
//if(x == y) return x;
if(deth[x] < deth[y]) swap(x, y);
while(deth[x] > deth[y])
x = f[x][lg[deth[x]-deth[y]]-1];
if(x == y) return x;
for(int i = lg[deth[x]]; i >= 0; --i)
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
int main() {
int n = read(), m = read();
for(int i = 1; i <= n; ++i) lg[i] = lg[i-1] + (1 << lg[i-1] == i);
for(int i = 1; i <= n-1; ++i) {
int x = read(), y = read();
add(x, y); add(y, x);
}
deth[0] = -1; dfs(1, 0);
for(int i = 1; i <= m; ++i) {
int x = read(), y = read(), z = read();
int xx = LCA(x, y), yy = LCA(y, z), zz = LCA(x, z), lca;
int d = max(deth[xx], max(deth[yy], deth[zz]));
if(deth[xx] == d) lca = xx;
else if(deth[yy] == d) lca = yy;
else lca = zz;
LL ans = len[x] + len[y] + len[z] - len[xx] - len[yy] - len[zz];
printf("%d %lld\n", lca, ans);
}
return 0;
}