CF76A

Portal

这是一道挺有意思的题,只是不知道为啥 CF 上 diff 只有 2200?可能因为是远古场吧。

首先考虑一个暴力:从小到大枚举金子数,然后显然最优银子数是递减的,这样一来便是一个 two-pointers,所有可能的最优情况一共有 (mathrm O(m)) 个。然后一路 two-pointers 下来,每次都暴力并查集或 DFS 判连通性,这样复杂度是 (mathrm O!left(m^2alpha ight))(并查集的删边并不是撤销,无法优化)。但是正解似乎和这个暴力一点关系都没有(

换个角度想:之前是想先确定金银数,然后看构出来的图;而我们可以从图中抽一些边,然后看要的最小金银数。显然,对于抽出来的一些边,要的金银数便分别是这些边的最大金银数(那么边的金银数可以看作边权)。要抽出来的边使得图连通的话,显然考虑取生成树。于是我们的任务就变成了求使得 (Gg+Ss) 最小的这样一个广义 MST。

广义 MST 怎么求呢?我们考虑 Kruskal 的本质,也就是正确性证明。它基于生成树的一个非常重要的性质:将一条非树边连入该生成树,将形成的环中异与加入边的一条边去掉,得到另一棵生成树;而任意两个生成树都可以通过上述操作互相转化。而一棵生成树是 MST 当且仅当任意一条非树边加入后,它是所在环中边权最大的(也就是无法通过上述操作使权值和变小),这个必要性显然,充分性随便反证。Kruskal 就是利用了这一点,搞出一个推论:任意一棵 MST 都包含图中最小边,亦即图中任意一条最小边都一定在至少一颗 MST 里,随便反证。那么我们 dark 选出任意一条最小边,然后考虑将这条边两端合并成一个点,问题归约为规模为 (n-1) 的问题,至此 Kruskal 正确性得证。

可见广义 MST 可以用 Kruskal 求需要满足任意时刻都存在一条边,若它是非树边那么以它作为对象做上述操作一定能减小生成树的总权值。而这题中要求的权值是个二维的,很显然不一定存在这样一条边。于是我们考虑消掉一维。

考虑枚举第一维,也就是金子数。那么剩下来的任务就是求一个一维权值的广义 MST,很显然可以 Kruskal,就按照普通 Kruskal 选边策略显然可证正确性。但是这样还是 (mathrm O!left(m^2alpha ight)),又回到了暴力(?

但是这个暴力是可优化的。注意到 MST 是一棵树,边数是 (mathrm O(n)) instead of (mathrm O(m))。一条边今朝不包含在 MST 里,以后永远也别想翻身(这也太显然了吧)。于是我们可以在 (g) 的从小到大枚举过程中,实时维护 MST 的边们,然后将新加的边暴力放进去跑 Kruskal,这样总边数显然是,(mathrm O(m)) 次每次基础边 (mathrm O(n)),添加的边的总量是 (mathrm O(m)),还要排序,所以总复杂度是 (mathrm O(nmlog))。然后这个 (log) 可以归并掉,但还要并查集,所以是 (mathrm O(nmalpha))

至此应该可以过了,但是 yyq 说「有更优秀的方法为什么不用呢」。考虑不一次增加 (g_i=g) 的那么多边,而一条边一条边加,这样显然会变更简单一些。考虑不再拘泥于 Kruskal,去掉并查集操作:注意到上面说的生成树的那个性质,看新加入的边加入后形成的环,能不能把原边弹劾掉。于是我们需要维护当前 MST 的邻接表,DFS、删边这一切都是 (mathrm O(n)) 的,所以总复杂度 (mathrm O(nm))

code

珍爱生命,远离抄袭!
原文地址:https://www.cnblogs.com/ycx-akioi/p/solution-cf76a.html