换根dp
引入
Problem
现在有一个无根树,要你确定一个根,使得其他点到这个根的距离最短。\(n \le 10^5\)
Solution
Thinking 1
枚举根,dfs暴力求距离,取最大值,时间复杂度\(\mathcal{O}(n^2)\)。
Thinking 2
如果让根的子树变成根,那个树的形态其实很多都没变!如果再来一次\(\mathcal{O}(n)\)的话,太浪费了!
我们考虑先选一个根节点(默认为1),然后dfs子树来更新。
假设我们现在已经通过第一次dfs算出了\(dp[1]\)(以1为根的答案),来求\(dp[2]\)。不难发现,\(2\)和\(A\)的深度都相比一开始减1,那么对答案的贡献就是减子树的大小,即\(siz[2]\),然后除了\(2\)和\(A\)以外的所有点深度都加1,对答案的贡献加\(n - siz[2]\)。
整理得
\[dp[2] = dp[1] - siz[2] + n - siz[2] = dp[1] + n - 2siz[2]
\]
推广到一般形式:
\[dp[v] = dp[x] + n - 2siz[v]
\]
不难发现只需要两次dfs,所以时间复杂度为\(\mathcal{O}(n)\)。
做法
1.先定一个根(一般是1),然后先算出答案,同时预处理一些转移需要的东西。
2.根据具体题目推式子转移。