prufer序列简介
将一棵无根树和一个值域在 ([1,n]) 之间的长为 (n-2) 的序列 一一对应
构造
每次选择一个标号最小的叶子结点删除掉,将删除的节点的父亲记录在 prufer 序列的末尾。重复此过程。
使用堆维护的话复杂度是 (O(nlog n)) 的。
线性构造
维护一个单调递增的指针 (p),初始时 (p) 指向编号最小的叶结点。每次我们删除一个节点的时候,如果其父亲变成叶子,记其父亲为(x)。若(x<p),则下一步直接删除(x),继续进行。否则的话让指针 (p) 自增直到遇到一个未被删除叶结点为止。证明也很简单,在(p)之前的度数为(1)的点要么已经被(p)自增的时候扫过去了,要么是扫过去了以后变成叶子,会被贪心的先选择。
时间复杂度(O(n))
还原
整体过程大概就是构造的逆变换。有一个关键性质是,设(d_i)为(i)的度数,那么(i)在prufer序列中的出现次数为(d_i-1)。我们可以根据prufer序列确定每一个顶点的度数。
朴素做法还是用堆维护编号最小的叶子节点,从前往后依次扫描prufer序列,当前prufer序列中的元素就是编号最小的叶子的父亲。时间复杂度 (O(nlog n))
线性还原
类似线性构造,我们将用堆维护编号最小的叶子换成单调递增的指针+贪心判断即可。时间复杂度(O(n))
应用
Cayley 公式
用于prufer序列与无根树的一一对应关系,我们可以得到
有(n)个点的完全图的有标号生成树个数为
也可以表述为:有(n)个点的本质不同有标号无根树的个数为(n^{n-2})
有标号有根树
直接在无根树中选择一个点作为根即可。或者可以理解为在构造prufer序列的时候剩下两个点,再选一个点作为叶子,另一个作为根。
方案数就是
有标号有根树森林
树的个数确定
假设数的个数为(m)
建一个虚点,连这(m)个节点,因为一个点的度数是 prufer 序列中的出现次数(+1),所以这个虚点要在 prufer 序列中出现 (m-1) 次,再加上是 (n+1) 个节点的有根树,也就是
数的个数不确定
如果我们不需要确定根的个数,即对所有(m)求和得到
限制度数的无根树
设度数为(d_i),方案数是
多个点的度数限制可以由此推广
特别的,如果所有点的度数都有限制
连通块建树
证明详见 OI wiki
有 (k) 个连通块,每个连通块大小为 (a_i),求将这些连通块连成树的方案数。
记 (sum a_i=n),答案为