题意:
给定两棵 \(n\) 个点的带边权树。
求包含 \(n\) 个点的,\(i\) 和 \(j\) 之间边权为 \(d_1\left(i, j\right) + d_2\left(i, j\right)\) 的完全图的最小生成树大小。
其中 \(d_x\left(i, j\right)\) 表示 \(i\) 和 \(j\) 两点在第 \(x\) 棵树上的距离。
数据范围:\(n\le10^5\)。
子问题:Tree MST。
先来考虑子问题的解法:
- 有一个结论:如果我们把边集分成两部分,对这两部分分别求 MST,然后再合并起来,就是原图的 MST。
- 由于问题建立在树上,因此考虑树分治。
- 在点分治的过程中,考虑跨过分治重心的路径。设分治重心为点 \(x\),\(f_u=dis_{u,x}+w_u\),那么把两个点 \(u\),\(v\)连起来的边权就是 \(f_u+f_v\)。很明显,对于当前分治重心控制的所有节点,肯定是都和 \(f\) 值最小的点连起来最优,将这些边加入边集中。
- 对于在同一个子树内的两个点 \(u\) 和 \(v\),这样连边的边权大于实际边权,但没有关系,这样肯定不优,而实际边权会在之后的递归中被考虑到,所以可以照样加进去。
- 最后对于选出来的边跑一遍 Kruskal 即可。
- 时间复杂度 \(\mathcal{O}(n\log^2n)\)。
考虑将子问题的解法扩展到当前问题。
对第二棵树点分治,那么对于当前分治重心 \(x\) 来说,两个点 \(u\),\(v\) 的边权就是 \(d_2\left(u,x\right)+d_2\left(v,x\right)+d_1\left(u,v\right)\)。
将 \(x\) 这一层的所有节点在第一棵树上的虚树拿出来,并且对每一个点 \(u\) 建一个虚点 \(u+n\),将它们俩连起来,边权为 \(d_2\left(u,x\right)\)。
对于虚树上的每一个点 \(u\),找到离它最近的虚点 \(fr_u\)。对于每一条边 \(\left(u,v\right)\),如果离它们两个点最近的虚点不同,那么在最终边集中加入 \(\left(fr_u,fr_v,w_{u,v}+dis_u+dis_v\right)\),其中 \(dis_u\) 表示 \(u\) 和与它最近的虚点的距离。对于最终边集跑一边 Kruskal 即可。
这样做为什么是对的?考虑加入到最终边集中的边边权一定不会小于实际边权(因为加进的边一定合法),对于最终最小生成树上的一条边 \(\left(u,v,w\right)\),当分治重心在 \(u\) 到 \(v\) 的路径上时,这条边就会加入。
时间复杂度 \(\mathcal{O}\left(n\log^2n\right)\)。