洛谷 P3478:[POI 2008] STA-Station ← 换根DP
【题目来源】
【题目描述】
给定一个 n 个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和最大。
一个结点的深度之和定义为该节点到根的简单路径上边的数量。
【输入格式】
第一行有一个整数,表示树的结点个数 n。
接下来(n-1)行,每行两个整数 u,v,表示存在一条连接 u,v 的边。
【输出格式】
输出一行一个整数表示你选择的结点编号。如果有多个结点符合要求,输出任意一个即可。
【输入样例】
8
1 4
5 6
4 5
6 7
6 8
2 4
3 4
【输出样例】
7 或 8
【数据范围】
对于全部的测试点,保证1≤n≤10^6,1≤u,v≤n,给出的是一棵树。
【算法分析】
● 换根 DP 是树形 DP 的一种重要技术,用于解决需要以树中不同节点为根分别计算答案的问题。其核心思想是在一次动态规划后,通过推导出换根时的状态转移公式,高效地计算出所有节点作为根时的结果,避免对每个根节点都进行一次 O(n) 的树形DP(那样总复杂度为 O(n²))。
● 对于大多数简单的树形 DP 问题,如计算子树大小、节点深度、简单路径统计等,算法通常对每个节点执行常数次操作,因此时间复杂度为 O(n)。
● 换根 DP 通常遵循一个固定的两遍 DFS 流程:
(一)第一次 DFS(固定根,收集信息)
(1)任选一个节点(通常为 1 号节点)作为初始根。
(2)进行一次自底向上的树形 DP,计算以该节点为根时,各子树的状态信息。这些信息通常包括:子树大小(siz[u])、子树内节点到根的距离和(dis[u])、或其他与问题相关的子树最优解。
(二)第二次 DFS(换根,推导全局)
(1)这是算法的关键。基于第一次 DFS 得到的信息,从初始根节点开始,进行第二次 DFS。
(2)在遍历过程中,当从父节点 u 走向子节点 v 时,利用已知的以 u 为根时的全局答案 dp[u],推导出以 v 为根时的全局答案 dp[v]。
(3)这个推导过程就是 “换根公式”,它分析了当根从 u 移到 v 时,哪些节点的贡献发生了变化(例如,深度增加或减少),并据此更新答案。
● 经典示例:所有节点到其他节点距离之和
这是一个最经典的换根DP问题,清晰地展示了换根公式的推导过程。
(1)问题:给一棵树,求以每个节点为根时,所有节点到该根节点的深度之和。
(2)定义:siz[u]:以 u 为根的子树中的节点数、dis[u]:以 u 为根时,所有节点到 u 的深度之和。

(3)步骤:
第一次 DFS:以节点 1 为根,计算 siz[u] 和初始的 dis[1]。
换根公式推导:当根从 u 换到其子节点 v 时,所有在 v 子树中的节点,到新根 v 的距离比到旧根 u 的距离减少1。这部分贡献总共减少 siz[v]。所有不在 v 子树中的节点(共 n - siz[v] 个),到新根 v 的距离比到旧根 u 的距离增加1。这部分贡献总共增加 n - siz[v]。
因此,dis[v] = dis[u] - siz[v] + (n - siz[v]) = dis[u] + n - 2 * siz[v]。
第二次 DFS:应用此公式,即可从 dp[1] 递推计算出所有节点的 dis[i]。
● 本题数据量达到了 10^6,所以在代码中加入如下语句(),避免 TLE。
当然,也可以使用“快读()”函数,代码如下。
【算法代码:邻接表存图】
【参考文献】

浙公网安备 33010602011771号