八段第一课树结构升级总结
八段第一课树结构升级总结
A 间隔选点-树上版本
解法
设 $f_{i,0/1}$ 表示当前是编号为为 $i$ 的点,是否有选。
然后当前节点选的状态就可以加上所有儿子不选的状态,而当前节点不选的状态则可以加上儿子选与不选的状态。
所以dfs即可。
代码
1 |
|
B 苹果树
解法
我们可以设 $f_{i,j,0/1}$ 表示当前停留在 $i$ 点,使用 $j$ 步 回/不回 到原点的最大价值。
那么对于一个点分三种情况。
- 走到儿子 $y$ 然后回来,那么可以由 $f_{i,step-k,0} + f_{y,k-2,0}$ ,也就是表示先使用 $step-k$ 步去其他的节点然后回来,然后用一步走到 $y$ ,然后用 $k-2$ 步走出最大价值回到 $y$ 点,最后再用一步回来。
- 走到儿子 $y$ 并不回来,最后停留在以 $y$ 为根的子树上。那么可以由 $f_{i,step-k,0}+f_{y,k-1,1}$ 转移,也就是说先用 $step-k$ 步去其他地方然后回来,最后用一步到 $y$ 点,并走出最大价值后不回来。
- 走到儿子 $y$ 并不回来,但最后不停留在以 $y$ 为根的子树上,那么可以由 $f_{y,k-2,0}+f_{i,step-k,1}$,也就是先走到 $y$ 子树后回来,再去其他节点,停留在以其他儿子为根的子树上。
那么我们就可以用树形dp,然后用一个类似背包的嵌套循环转移
代码
1 |
|
C树上最远距离
解法
根据直径的性质,其实每个点在树上的最远距离的终点都一定在直径的两个端点上。
所以直接找出直径,然后算出每个点与直径的距离比较大小就好了。
代码
1 |
|
G 树的直径-加强版
解法
首先有一个性质,就是所有直径的公共边都是连续的。
所以我们可以随便找出一条直径,遍历上面的点,从直径的左端点开始,找出每个点不经过直径的最长链,如果发现最长链的长度等于了这个点到右端点的长度,那么右边的边都不可能是公共边了,如图:

我们发现直径上有一个点能延申出的最长路与右端点相等,那么这个点往右的自然都不是公共边了。
同理,还可能出现与往左那段的距离相等的情况,所以在第一轮遍历后还得从这个点再往左遍历,看是否到左端点的距离等于当前点的最长路,两个点区间的边即为答案。
代码
1 |
|
H 动态树直径
解法
假设我们当前的直径的两个端点是 $x$,$y$,那么假设我们添加了两个点 $a$,$b$,那么根据直径的定理,我们只需要看 $(x,a)$ 和 $(a,y)$ 的长度是否大于原来的直径就行了,因为 $a,b$ 同个深度且父亲相同,所以可以省略 $b$。
路径长度用 $lca$ 算。
代码
1 |
|
I 不相交路径
解法
可以贪心,首先按照路径的lca的深度排序,越深越好,因为这样影响最小,然后每次都查看每条路径,如果路径上没有点被其他路径覆盖过,就选然后标记。
最后统计的即是答案。
代码
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ChenZQ's blog!
