图论复习——最小生成树MST

知识点

  • MST的构造
    Boruvka算法常用于解决这类问题:给你n个点,每个点有点权,任意两个点之间有边权,边权为两个点权用过某种计算方式得出,求最小生成树。动图

  • MST上的确定性和存在性问题

  • 最小生成树的两个性质:
    (1) 不同的最小生成树中,每种权值的边出现的个数是确定的
    (2) 不同的生成树中,某一种权值的边连接完成后,形成的联通块状态是一样的
    可以用这两个性质做最小生成树计数

  • Kruskal重构树

  • a , b a,b a,b路径上最长边最短: “最短的最长边”一定在MST上,所以我们求一下MST,再在MST上找 a , b a,b a,b路径上的最长边。

  • n n n个点 m m m条边的无向连通图上任两点的最短距离, m − n m-n mn很小:随便建一棵生成树,把图看成树上挂几条边 CF1051F The Shortest Statement

  • trick: 对区间 [ l , r ] [l,r] [l,r]操作 ⇒ \Rightarrow 连边 l → r + 1 l\to r+1 lr+1

CF888G Xor-MST

在这里插入图片描述
Boruvka + 01Trie树

Boruvka算法简介:
对图中所有的点 i i i,找到 i i i连向其它点的最小边,如果这条边还没加进 M S T MST MST,就把它加上。执行完后,把每个连通块缩成点。
不断重复上面的操作,直到只剩下一个连通块。
时间复杂度 O ( ( m + n ) l o g n ) O((m+n)logn) O((m+n)logn)

此题中,要让 a i ⊕ a j a_i \oplus a_j aiaj最小,就让 a i , a j a_i,a_j ai,aj的高位尽量保持相等。
假设我们现在运行Boruvka,并且目前只剩两个连通块,那么设 p p p表示所有的 a a a的第1~ ( p − 1 ) (p-1) (p1)位(从高位数起)都相等,在第 p p p位才出现不同。

那么在这两个连通块中一定不会有 连接 i , j i,j i,j a [ i ] a[i] a[i]的第 p p p位和 a [ j ] a[j] a[j]的第 p p p位不同的边 ,也就是说 a a a值的第 p p p位为1的点构成一个连通块, a a a值的第 p p p位为0的点构成一个连通块。

那么最后加入的边一定是 连接 i , j i,j i,j a [ i ] a[i] a[i]的第 p p p位和 a [ j ] a[j] a[j]的第 p p p位不同的边,用 01Trie树 找到这样的最小边。

加完最后一条边,我们再递归回去,把 a a a值的第 p p p位为1的点连成一个连通块, a a a值的第 p p p位为0的点连成一个连通块。

Code

CF1108F MST Unification

在这里插入图片描述
Blog

Code

CF733F Drivers Dissatisfaction

在这里插入图片描述
根据贪心,把 S S S的费用全部用来降一条边的权值不比用来降多条边的权值劣。

枚举每一条边,看一下降这条边的答案是多少,最后取最优结果即可
先用Kruskal建出MST,设 s u m sum sum为MST里各边的权值和。

  • 如果降树边:
    答案为 s u m − ⌊ S c i ⌋ sum-\lfloor\frac{S}{c_i}\rfloor sumciS(保证降完后该边是在MST里的)

  • 如果降非树边:
    把降完权值后的非树边连上,原MST上出现一个环,我们找到环上最大的边删掉即为新的MST。
    每条非树边对应的环上最大边边权可以用倍增预处理出来。

Code

CF1416D Graph and Queries在这里插入图片描述

Kruskal重构树
不会删边。所以考虑离线,按时间倒序进行操作,删边变成加边。

但是遇到的麻烦是,操作 1 是正序进行的,如果我们倒序操作,就不知道当前哪些点 p u = 0 p_u=0 pu=0 了。

解决方法是,先倒序遍历一遍所有操作,按“加边”的顺序,建出重构树。重构树优美的性质是,对任意一个节点 v,在某个时刻之前和它连通的节点,恰好在重构树上 v 的某个祖先的子树中。并且我们可以通过树上倍增,在 O ( l o g n ) O(logn) O(logn) 的时间内找到这个祖先。

建出重构树后,我们回到正向的时间线。按正序处理所有询问(操作 1)。前面说过,在某个时刻和 v 连通的节点,在 v 某个祖先的子树中。先倍增找到这个祖先。它的子树是 dfs 序上连续的一段。我们预处理出重构树的 dfs 序,那么问题转化为求区间最大值,支持单点修改。可以用线段树维护。

Code

CF1253F Cheap Robot

在这里插入图片描述

法一
先预处理出 d i s u dis_u disu表示 u u u到最近的充电中心的距离(求多源最短路戳这
a a a b b b的路径 能经过边 ( u → v , w ) (u\to v,w) (uv,w),当且仅当 c − d i s u − w ≥ d i s v c-dis_u-w\geq dis_v cdisuwdisv,即 d i s u + d i s v + w ≤ c dis_u+dis_v+w\leq c disu+disv+wc

那么问题变成求一条从 a a a b b b的路径使得路径上每条边的 d i s u + d i s v + w dis_u+dis_v+w disu+disv+w的最大值最小(明显是满足条件的最小的 c c c)。

可以用Kruskal重构树实现,
也可以用NOIP2013货车运输/BZOJ3732 Network的套路实现:
“最短的最长边”一定在MST上,所以我们求一下MST,再在MST上找 a , b a,b a,b路径上的最长边。

法二
在任意两个充电中心 i , j i,j i,j之间连边,边权 d i , j d_{i,j} di,j为原图上 i , j i,j i,j之间的最短距离。
那么 c c c为新图中从 a a a b b b的路径上最长边的最小值。法一中已经解决了这个问题。

现在的问题是如何求 d i , j d_{i,j} di,j,这里介绍一种剪枝方法:
先跑多源最短路,对每个点 i i i求出离 i i i最近的充电中心 f i f_i fi和到 f i f_i fi的最短距离 d i s i dis_i disi,然后枚举原图中的每条边 ( u → v , w ) (u\to v,w) (uv,w),在新图上连边 f u → f v f_u\to f_v fufv,边权 w ′ w' w d i s u + d i s v + w dis_u+dis_v+w disu+disv+w
可以证明 m i n f u → f v { w ′ [ f u → f v ] } = d u , v min_{fu\to fv}\{w'[fu\to fv]\}=d_{u,v} minfufv{ w[fufv]}=du,v。同样的剪枝方法见这里

Code

CF1051F The Shortest Statement

在这里插入图片描述

m − n < = 20 m-n<=20 mn<=20,所以可以看成是一棵树上挂了几条边
树上求两点间最短距离用LCA
多出来的边怎么办?
找出所有非树边的端点记为特殊点,枚举u,v间路径过每一个特殊点的情况
(u,v路径要过非树边一定过特殊点,枚举过点的情况是因为可以用dijkstra)
因为u,v间路径只有 只过树边 和 不是只过树边 2种,所以一定不会漏(不保证不重,但没关系)

Code

CF1120D Power Tree

在这里插入图片描述
Blog

Code

Guess you like

Origin blog.csdn.net/Emma2oo6/article/details/120760825