Boruvka算法解决某些问题超级好用。
这些问题形如,给你n个点,每个点有点权,任意两个点之间有边权,边权为两个点权用过某种计算方式得出。
求最小生成树。
通常用O(log n)的时间可以找到与点i连边的边权最小的j。
我们考虑这样一个求最小生成树的算法:
考虑维护当前的连通块(初始每个点为独立的一个连通块)
对每个连通块,找到一条与该连通块相连的,且另一端点不在此连通块中的边权最小的边。
将所有的这些边都加入最小生成树,注意,当加入一条边时需判断该边的两端点是否在同一连通块。
重复若干遍上述操作,直到图连通。
这个算法叫Boruvka算法。
复杂度分析:每次连通块个数至少减半,则复杂度为O((n+m)logn),还有个并查集假装是O(1)
但是此算法通常不用于求裸的最小生成树(Kruskal多好用)
可是在解决上述问题时,往往有奇效。
我们发现,我们只需要求出与每个连通块相连的边权最小的边即可,在这种类型的题目中,这个东西复杂度一般为O(n log n)
所以我们就可以在O(n log^2 n)的复杂度下解决此类问题。
Atcoder keyence2019 E
#include <cstdio> #include <iostream> #include <cstring> #define MN 201000 typedef long long ll; int fa[MN]; int c1[MN], c2[MN]; int Min[MN]; ll D; int a[MN]; int X[MN], Y[MN]; int x[MN], y[MN]; ll ans = 0; int bl; int n; int Abs(int a) { return a > 0 ? a : -a;} ll F(