prufer序列学习笔记

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-2} ]

也可以表述为:(n)个点的本质不同有标号无根树的个数为(n^{n-2})

有标号有根树

直接在无根树中选择一个点作为根即可。或者可以理解为在构造prufer序列的时候剩下两个点,再选一个点作为叶子,另一个作为根。

方案数就是

[n^{n-1} ]

有标号有根树森林

树的个数确定

假设数的个数为(m)

建一个虚点,连这(m)个节点,因为一个点的度数是 prufer 序列中的出现次数(+1),所以这个虚点要在 prufer 序列中出现 (m-1) 次,再加上是 (n+1) 个节点的有根树,也就是

[inom{n-1}{m-1}n^{n-m}=inom{n}{m}mn^{n-m-1} ]

数的个数不确定

如果我们不需要确定根的个数,即对所有(m)求和得到

[sum_{m=1}inom{n-1}{m-1}n^{n-m}=sum_{m=0}inom{n-1}{m}n^{n-1-m}=(n+1)^{n-1} ]

限制度数的无根树

设度数为(d_i),方案数是

[inom{n-2}{d_i-1}(n-1)^{n-d_i-1} ]

多个点的度数限制可以由此推广

特别的,如果所有点的度数都有限制

[inom{n-2}{d_1-1,d_2-1,d_3-1,cdots,d_n-1}=frac{(n-2)!}{prod(d_i-1)!} ]

连通块建树

证明详见 OI wiki

(k) 个连通块,每个连通块大小为 (a_i),求将这些连通块连成树的方案数。

(sum a_i=n),答案为

[n^{k-2}prod a_i ]

原文地址:https://www.cnblogs.com/harryzhr/p/14960543.html