Boruvka 学习笔记

Boruvka 算法是一种求解最小生成树的算法。每轮对于每个连通块,找出一条连接其他连通块的最短边,并将这些边加入最小生成树中。由于每轮连通块数量减半,所以是 \(O((n+m)\log n)\) 的。

连通块使用并查集维护。其实并查集是 \(O(\log n)\) 还是 \(O(\alpha(n))\) 的没有影响,因为一共只会合并 \(n-1\) 次。

该算法常用于求解稠密图的最小生成树。

例题

P9701

定义特殊边为 \(P\) 中的边,平凡边为其他。特殊点为连接特殊边的点,平凡点为其他。

发现 \(n\) 非常大,而与特殊点只有 \(O(m)\) 个,考虑将一段平凡点缩成一个,这样一段里相邻的两个连接一条长度为 \(1\) 的平凡边最优。缩完后就只有不超过 \(4m+1\) 个点。

Boruvka 算法中需要枚举最小出边。枚举特殊边是 \(m\) 的,而枚举平凡边则不可接受。事实上我们不用枚举每一条平凡边,由于只求最小的那一条,所以对于点 \(x\) 往前后暴力跳就好了。

现在证明暴力跳的时间复杂度是对的。跳到 \(y\) 且不满足是平凡出边时会有两种情况。

  1. \((x,y)\) 是一条特殊边。由于特殊边只有 \(m\) 条,所以每轮 1 情况的总和是 \(O(m)\) 的。
  2. \(y\)\(x\) 属于同一连通块。这时需要维护一个 prev/next 数组来跳过一整段同一连通块的,使得 1,2 两种情况是交替出现的,所以每轮 2 情况的总和也是 \(O(m)\) 的。

CF1550F

考虑将 \(x,y\) 两点之间连一条边权 \(w=||a_x-a_y|-d|\) 的边,表示两点可以一次到达当且仅当 跳跃距离范围设置 不小于 \(w\)

于是能否从 \(s\) 到达 \(i\) 就是判定 \(s\)\(i\) 两点是否有一条路径满足所有边的边权不大于 \(k\)。有一个经典的 trick 是两点之间最小的路径上的边权最大值等于两点在 MST 上的路径边权最大值。

使用 Boruvka 求解 MST。考虑怎么找到最小的 w 的 \(y\)。分类讨论一下得:

\[w=\begin{cases} |a_x-a_y-d|,x>y\\ |a_y-a_x-d|=|a_x+d-a_y|,x<y \end{cases} \]

分别找离 \(a_x-d\)\(a_x+d\) 最近的就好了。


CF888G

看到异或想到 0-1 trie,发现在 trie 上 LCA 深度越大异或越小。考虑从根递归下去,对于有两个儿子的点,将两个儿子子树合并为一个连通块后,在 trie 上找到最小边合并即可。

posted @ 2024-10-24 08:01  ASnown  阅读(1)  评论(0编辑  收藏  举报