虚树
在一些问题中
有一个朴素的想法
经过观察可以发现
- 若 $\rm LCA(u,v)=v$
那么直接将 $u$ 入栈, 。 - 若 $\rm LCA(u,v)$ 是栈中某个不为 $v$ 的点
则弹栈直到 $\rm LCA(u,v)$, 每弹一个就向栈中比它深度多 $1$ 的结点连边, 最后并把 $u$ 入栈, 。 - 若 $\rm LCA(u,v)$ 不在栈中
那么弹栈直到栈顶的 $\rm dfs$ 序小于 $\rm LCA(u,v)$ 的 $\rm dfs$ 序, 每弹一个就向栈中比它深度多 $1$ 的结点连边, 并把最后一个弹出的结点向 $\rm LCA(u,v)$ 连边, 最后把 $\rm LCA(u,v)$ 和 $u$ 入栈, 。
不难发现这样一定是对的
在一棵有 $n$ 个点的树上建立一颗有 $k$ 个点的虚树的时间复杂度为 $\Theta(k\log n)$
经典例题
[SDOI2011] 消耗战
首先有一个暴力 $\rm DP$
- 若 $v$ 为关键点
那么必须切断这条边, 有 $dp_u=dp_u+w_{u,v}$, - 若 $v$ 不为关键点
那么可以切断这条边也可以从 $dp_v$ 转移, 故有 $dp_u=dp_u+min\{dp_v,w_{u,v}\}$,
最终答案就是 $dp_1$
观察到 $\sum k\leqslant 5e5$
建虚树之前需要记 $M_u$ 表示从 $1$ 到 $u$ 的路径上最短的边权
时间复杂度 $\Theta(\sum k\log n)$
[HEOI2014] 大工程
首先建虚树
- 对于两两之间距离之和
可以计算每条边的贡献, 。 - 对于最大$/$最小值
可以树形 $\rm DP$ 或点分治, 。
时间复杂度 $\Theta(\sum k\log n)$
[SDOI2015] 寻宝游戏
我们发现如果将虚树建出来
于是我们考虑动态维护虚树的边权之和
时间复杂度 $\rm \Theta(n\log n)$