前言
在 亲 爱 的 马 基 佬 的 要 求 下 没 有 贴 代 码 \color{white}{在亲爱的马基佬的要求下没有贴代码} 在亲爱的马基佬的要求下没有贴代码 (((
额 我也不知道为什么要发出来以及为什么要起这个标题 大概是因为好玩吧。
总码长 3.5k。然而在码到 3.2k 的时候 cindy 走过来顺手把我电脑关了。
曾经我也想过一了百了,但是好在我在码了 2.7k 的时候顺手备份了一下。
正文
Description
给定 N N N 个点, M M M 条边,求 严格 次小生成树。
严格次小生成树的定义:边权和最小的满足边权和 严格大于 最小生成树边权和的生成树。
Solution
我们来捋一下整道题的思路。
-
最小生成树
看到次小生成树,许多人都会联想到最小生成树。
相信大家都会用 Kruskal 算法求解最小生成树。所以这一步我们跳过。
-
不严格次小生成树
如何把最小生成树 M M M 转换为不严格次小生成树 M ′ M' M′?
对于任意一条 不存在于 M M M 中的 边 ( u , v , w ) (u,v,w) (u,v,w),我们将其加入最小生成树。
此时的最小生成树已经不是树了,因为它有 n n n 个点, n n n 条边。也就是说,图中一定存在至少一个环。删除这个环上的任意一条边,图还原为树。
这个环是在加入边 ( u , v , w ) (u, v, w) (u,v,w) 后产生的,所以点 u u u 和点 v v v 一定在环上。
显然,令 t = lca ( u , v ) t=\operatorname{lca}(u,v) t=lca(u,v),则这个环由原生成树上两条简单路径 u → t u\to t u→t、 v → t v\to t v→t 和边 ( u , v , w ) (u,v,w) (u,v,w) 组成。
为了让图还原为树,我们需要删除这个环上的边。这条边不能是我们刚刚加入最小生成树的边 ( u , v , w ) (u, v, w) (u,v,w),因为我们要用它尝试让最小生成树的权值变大;所以我们就只能在 u → t u\to t u→t 和 v → t v\to t v→t 中选择。
我们找到 u → t u\to t u→t 和 v → t v\to t v→t 上权值最大的边,用 ( u , v , w ) (u, v, w) (u,v,w) 替换,就能得到不严格次小生成树。
在使用倍增法维护最小生成树的 LCA 的同时,我们维护一个最大值数组 p p p,其定义与倍增祖先数组 f f f 的定义类似:
p[i][j]
表示点 i i i 向上(树根方向)的 2 j 2^j 2j 条边中,边权的最大值。其转移则类似于 ST 表求 RMQ:
for(int j = 1; j <= 20; ++j) { f[i][j] = f[f[i][j-1]][j-1]; p[i][j] = max (p[i][j-1], p[f[i][j-1]][j-1]); }
于是我们可以轻松地得到路径上的最大边权 w ′ w' w′,则最后的答案为 M ′ = M − w ′ + w M'=M-w'+w M′=M−w′+w。
比较对于所有边生成的 M ′ M' M′,取其最小值为答案,因为 M ′ M' M′ 必须满足在所有可生成的树中,除了 M M M 权值最小。
-
严格次小生成树
我们思考,不严格次小生成树操作过程中的哪一步使得其不严格?其实就是因为 w ′ w' w′ 可能与 w w w 相等。
我们专门针对这个问题处理,同时记录 u → t u\to t u→t 和 v → t v\to t v→t 中的最大值和 严格 次大值,当最大值与 w w w 相等时,就弃用最大值,使用次大值。严格次大值的维护方法与最大值类似。
以及,我绝对没有模仿某个帖子。绝对没有。