跳到主要内容

「45」树的直径

定义​

备注

给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径上的边权之和。树中最远的两个节点之间的距离被称为 树的直径。

危险

下面我们讨论的前提均为边权非负。

性质1​

提示

从任意点出发,最远点一定可以作为某条直径的端点。

任取一个点 ss,找到距离 ss 最远的点 AA。那么 AA 一定是某条直径的端点。再从 AA 出发,找到最远点 BB,则 A→B A\rightarrow B 就是一条直径。

证明​

将 ss 作为根节点,任取树的一条直径 U∼VU \sim V, UU 和 VV 的 LCA 为点 TT。考虑 UU 和 AA 的LCA 点 PP 与 TT 的位置关系。

情况1​

点 PP 位于 TT 和 SS 之间,包括 TT 和 SS。

因为 SA≥SVSA \ge SV,所以 PA≥PVPA \ge PV,所以 PU+PA≥TU+TVPU + PA \ge TU + TV。

而 UVUV 已经是树的一条直径,是树中所能得到的两点间的最长距离。所以 UAUA 也是树的直径。因此 AA 是某条直径的端点。

从直径的一个端点出发,找到的最远点就是直径的另一个端点。

情况2​

点 PP 位于 TT 和 UU 之间,包括 UU。

SA≥SUSA \ge SU,所以 TA≥TUTA \ge TU,所以 TA+TV≥TU+TVTA + TV \ge TU + TV。因此,可以得知 AVAV 也是图的一条直径。

危险

该性质的成立前提是边权均为非负。

在情况 1 中,我们使用了 PV≤TVPV \le TV,PU≤TUPU \le TU。这两个不等式成立的前提是 PT≥0PT \ge 0。负权边会破坏这里的前提。

性质2​

提示

直径的两个端点一定是叶子

如果 AA 不是叶子,那么除了通向 BB 的方向以外还可以继续延伸;由于边权为正,就能得到一条比 A−BA-B 更长的路径,矛盾。

危险

注意边权为正这一点。以及若根节点的度数为 11,那么根节点也有可能作为直径的一个端点出现。

性质3​

提示

任意点的最远点,一定可以在一条固定直径的两个端点中找到。

设从 xx 出发,所能到达的最远点为 yy。

设 PP 是 xx 到直径 A−BA-B 的接入点,QQ 是 yy 到直径 A−BA-B 的接入点。

情况1​

x、yx、y 的接入点不同

ABxyPQ

此时因为 Qy≤QBQy \le QB,所以 xy≤xBxy \le xB。因此,将 yy 换成 BB,结果不会更差。

情况2​

接入点是同一个点,甚至 xx 和 yy 接入到直径 ABAB 之前就已经合并。

ABxyP ABxyQP

无论哪种情况,PB≤PyPB \le Py,因此,xB≤xyxB \le xy。

性质4​

定义树上节点 xx 的偏心距 e(x)e(x) 为从 xx 出发,所能到达最远节点的距离。

树的中心是指偏心距最小的节点。

提示

所有直径一定经过树的中心。

性质5​

提示

一棵树上,一定存在一个点 pp 被这棵树的所有直径经过。

性质6​

提示

任意两条直径一定有且仅有一个极长连续段(可以只是一个点)重合。若两条直径共用一个端点,这个端点也算重合。

树形 DP 求树的直径​

设树根为 11 号节点,D[x]D[x] 表示从节点 xx 出发走向以 xx 为根的子树,能够到达的最远节点的距离。

设 xx 的子节点为 y1,y2,⋯ ,y_1, y_2, \cdots, ,那么

D[x]=max{D[yi]+e(x,yi)}D[x] = max\{D[y_i] + e(x, y_i) \}

设 F[x]F[x] 表示子树 xx 中,经过 xx 的最长链的长度。

那么,以 xx 为端点,向其子树出发的链中,选择最长的两条合在一起便是在子树 xx 中, 经过 xx 的最长链。

因此

F[x]=max{D[yi]+e(x,yi)+D[yj]+e(x,yj)}F[x] = max \{ D[y_i] + e(x, y_i) + D[y_j] + e(x, y_j) \}

在实际实现的过程中,我们没必要分别枚举 i,ji, j 来计算答案。在依次枚举 xx 的子节点的过程中,令 D[x]D[x] 保存当前所得到的 D[y]+e(x,y)D[y] + e(x, y) 的最大值,若当前节点为 yiy_i,通过 yiy_i 所能得到的最长链为 D[x]+d[yi]+e(x,yi)D[x] + d[y_i] + e(x, y_i),经过当前节点以后,D[x]D[x] 更新为 max⁡{D[x],D[y]+e(x,yi)}\max \{D[x], D[y] + e(x, y_i) \}。

void dp(int x) {
v[x] = 1;
for (auto [y, z]: e[x]) {
if (v[y]) continue;
dp(y);
ans = max(ans, d[x] + d[y] + z);
d[x] = max(d[x], d[y] + z);
}
}

两次 BFS 求树的直径​

  1. 从任意一个节点出发,通过 BFS 或 DFS 对树进行一次遍历,求出与出发点距离最远的节点,记为 pp。
  2. 从节点 pp 出发,通过 BFS 或 DFS 对树再进行一次遍历,求出与 pp 距离最远的节点,记为 qq。

从 pp 到 qq 的路径就是树的一条直径。