定理:树的各条直径有公共部分
那就找到一条直径(两遍 $\text{dfs}$ ),找到两个端点 $\text{L, R}$,标记一下每个点是否在直径上($\text{tag}$ 数组),然后找公共部分的两端 $\text{L1, R1}$。
找 $\text{L1, R1}$:从左往右遍历直径上的点作为 $\text{L1}$,以 $\text{L1}$ 为根 $\text{dfs}$($\text{tag}$ 过的点不搜),如果搜到的最长链长度 $\text{dp1[L1]}$ 等于 $\text{dis(L1, R)}$ 就退出,此时 $\text{L1}$ 右边的直径上的边都不可能成为公共部分,因为在 $\text{L1}$ 处出现了分叉。$\text{R1}$ 同理。
(其实这里交换 $\text{L1, R1}$ 好一点)
#include <bits/stdc++.h>
#define int long long
#define N 200005
using namespace std;
struct node { int v, w; };
vector<node> g[N];
int dp[N], dp1[N], n, pt;
int dep[N], fa[N][20];
int L, R, len, L1, R1;
int tag[N], nxt[N];
void dfs1(int x, int f) {
dep[x] = dep[fa[x][0] = f]+1;
for(int i = 1; i < 20; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for(auto i : g[x]) {
int v = i.v, w = i.w;
if(v == f) continue;
dp[v] = dp[x]+w;
if(dp[v] > dp[pt]) pt = v;
dfs1(v, x);
}
return;
}
int Lca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = 19; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 19; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int dis(int x, int y) { return dp[x]+dp[y]-2*dp[Lca(x, y)]; }
void dfs2(int x, int f) {
for(auto i : g[x]) {
int v = i.v, w = i.w;
if(v == f || tag[v]) continue;
dp1[v] = dp1[x]+w;
if(dp1[v] > dp1[pt]) pt = v;
dfs2(v, x);
}
return;
}
void dfs3(int x, int f) {
dep[x] = dep[fa[x][0] = f]+1;
for(int i = 1; i < 20; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for(auto i : g[x]) {
int v = i.v, w = i.w;
if(v == f) continue;
dp[v] = dp[x]+1;
dfs3(v, x);
}
return;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n;
for(int i = 1, u, v, w; i < n; i++) {
cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
dp[1] = 0, dfs1(1, 0), L = pt;
dp[pt] = 0, dfs1(pt, 0), R = pt, len = dp[pt];
int tmp = R;
while(tmp != L) tag[tmp] = 1, nxt[fa[tmp][0]] = tmp, tmp = fa[tmp][0];
L1 = L;
while(L1 != R) {
dp1[L1] = 0, pt = L1, dfs2(L1, 0);
if(dp1[pt] == dis(L1, R)) break;
L1 = nxt[L1];
}
R1 = R;
while(R1 != L) {
dp1[R1] = 0, pt = R1, dfs2(R1, 0);
if(dp1[pt] == dis(L, R1)) break;
R1 = fa[R1][0];
}
dp[1] = 0, dfs3(1, 0);
cout << len << '\n' << dis(L1, R1) << '\n';
return 0;
}