[学习笔记] prufer序列
prufer序列
这个东西很早以前就听说过了,现在来系统地学习一下吧。
感谢 OI Wiki,每次它都能让我看懂,然后我就把他上面的抄下来了。
\(\tt prufer\) 序列可以将一个带标号 \(n\) 个节点的树用 \([1,n]\) 中的 \(n-2\) 个整数表示,可以理解为完全图的生成树和数列之间的双射,也正是这个特性它可以用于关于树的组合计数问题上。
如果我们要对树建立 \(\tt prufer\) 序列,那么每次选择一个最小的叶节点然后把他删掉,然后在序列中加入他连向的那个节点,重复 \(n-2\) 次后会剩下两个节点,用堆来维护可以做到 \(O(n\log n)\)
那么怎么用 \(\tt prufer\) 序列构建树呢?首先我们知道最后一定会剩下 \(n\),而且每个点的度数是在序列中的出现次数\(+1\),所以根据 \(\tt prufer\) 序列可以得到每个点的度数,那么使用类似的方法,我们找到编号最小的度数为 \(1\) 的节点,把他和当前考虑到的序列上的点连边,然后度数同时减去 \(1\) 即可,用堆来做同样是 \(O(n\log n)\) 的。
现在我们就能用 \(\tt prufer\) 序列来造毒瘤数据了,下面来看几道例题。
图连通方案数
题目描述
一个 \(n\) 个点 \(m\) 条边的无向图有 \(k\) 个连通块,问有多少种方案添加 \(k-1\) 条边能使他变成一棵树。
这个题目的应用:点这里看
解法
已知第 \(i\) 个连通块的大小为 \(s_i\),现在我们套 \(\tt prufer\) 序列,但是直接连上 \(k-1\) 条边会有点问题,因为每个连通块大小不同,一棵树的方案会和每个连通块连出去的边数有关,那么我们可以设第 \(i\) 个连通块的度数为 \(d_i\) 来表示方案。
对应到 \(\tt prufer\) 序列中就是强制第 \(i\) 个连通块出现了 \(d_i-1\) 次,这个可以直接组合数:
再乘上连通块内部选点的方案数就是:
这个东西看似无法化简,但是如果你知道 广义二项式定理 的话:
那么令 \(x_i=s_i,y_i=d_i-1\),我们就可以直接套公式了: