基础知识
\(prufer\) 序列是一种 \(n\) 个节点的有标号无根树与 \(n-2\) 的序列的双射关系
树转序列:每次选出编号最小的 叶节点,将其删去,并将其父亲加入序列,直到还剩两个点
线性构建:
void T_P(){
for(int i=1;i<n;i++)fa[i]=read(),deg[fa[i]]++;
for(int i=1,j=1;i<=n-2;i++,j++){
while(deg[j])j++;
p[i]=fa[j];
while(i<=n-2&&(!(--deg[p[i]]))&&p[i]<j)p[i+1]=fa[p[i]],i++;
}
}
序列转树:枚举最小的点,连向序列的第一个元素
void P_T(){
for(int i=1;i<=n-2;i++)p[i]=read(),deg[p[i]]++;p[n-1]=n;
for(int i=1,j=1;i<=n-1;i++,j++){
while(deg[j])j++;
fa[j]=p[i];
while(i<n-1&&(!(--deg[p[i]]))&&p[i]<j)fa[p[i]]=p[i+1],i++;
}
}
prufer序列的性质
- 由于映射关系唯一,那么树的个数由序列的个数决定,于是 \(n\) 个节点的有标号无根树个数为 \(n^{n-2}\)
- 最后剩下的两个点,一定有一个是编号最大的点
- 考虑最后剩下的一条边一定是编号最大点向其父亲(或其最大编号的儿子)的连边,那么序列里的剩下 \(n-2\) 个数恰好对应树里剩下的边
- 一个度数为 \(deg\) 的节点其在 \(prufer\) 序列里出现 \(deg-1\) 次
经典例题
考虑由性质可知,对于点 \(i\),在序列中出现 \(deg_i-1\) 次
序列总长度为 \(n-2\),每个点出现 \(deg_i-1\) 次,相当于多重集的排列,答案即为:\(\frac{n-2}{\prod deg_i-1}\)
设每个连通块点的个数为 \(s_i\),那么如果这个连通块向外总度数为 \(d_i\),那么方案数为 \(s_i^{d_i}\)
那么对于每个 \(d_i\) 序列,答案为 \(\displaystyle\binom{k-2}{d_1,d_2,...,d_k}\prod s_i^{d_i}\)
发现和多项式定理类似
于是转化为 \((d_1+d_2+...+d_k)^{k-2}\prod s_i\)
即 \(n^{k-2}\prod s_i\)
可以看做背包模型,将每个点看做价值为 \(f(deg_i)\),体积为 \(deg_i-1\) 的物品去填充体积为 \(n-2\) 的背包
背包过程中可以顺便记录转移,之后用 \(prufer\) 将序列转化成树