9C 生成树很爽(tree)

懒得抄题面了,直接放吧

alt text

alt text


首先是注意边权很小,记 \(f(i)\) 表示加入了边权 \(w\le i\) 的所有边后的连通块数量。

那么连通块的减少量 \(f(i-1)-f(i)\) 即为边权为 \(i\) 的边的贡献次数。


现在考虑求 \(f(i)\),只用维护每前 \(j\) 层的连通块数量,可以把边权扔掉了。

考虑在分层图上加入第 \(j\) 层后联通块数量的增量 \(F_j\)。

由一个浅显的暴力出发:初始 \(F_j=n\)。然后枚举 \(m\) 条边,每次成功的合并让 \(F_j\leftarrow F_j-1\)。

一个重要的信息是,\(F_j\) 只由第 \(j-1\) 层的连通性决定。

对连通性的一个观察是:若两个点在第 \(j-1\) 层连通,那么在第 \(j\) 层也连通,考虑连通其的路径整体抬升一层即证。

换句话说,整个过程中合并次数是 \(\mathcal O(n)\) 的,如果我们只处理所有首次合并的情形,即可做到线性。

记点 u 的所有出点为 \(S(u)\),对 \(S(A)\) 表示集合 \(A\) 内所有 \(u\) 的 \(S(u)\) 的并。

在第 \(0\) 层,我们选任意代表元 \(s_u\in S(u)\),将 \(S(u)\) 中其他点都与 \(s_u\) 标记在第 \(1\) 层合并。

接下来,对于任意两个在第 \(j\) 层的连通块 \(A,B\) 合并时,\(S(A)\) 与 \(S(B)\) 内部已分别连通,将 \(s_A\) 与 \(s_B\) 对应的连通块标记在 \(j+1\) 层合并即可。

每个有效合并最多产生一个有效时间,复杂度 \(\mathcal O((n+m)\alpha(n)+l)\)。


但是我们还是需要维护连通块数。具体的,我们记 \(a_j\) 表示第 \(j\) 层的连通块数,\(b_j\) 表示其中 \(S\) 不为空的连通块数,合并时可以简单维护。

即有 \(F_j=a_j-b_{j-1}\),即删去所有有出边的连通块(\(b_{j-1}\) 个),然后合并为 \(a_j\) 个。

posted @ 2026-10-12 12:32  CuteNess  阅读(13)  评论(0)    收藏  举报