prufer序列

基础知识

\(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\)

经典例题

P2290 [HNOI2004]树的计数

考虑由性质可知,对于点 \(i\),在序列中出现 \(deg_i-1\)
序列总长度为 \(n-2\),每个点出现 \(deg_i-1\) 次,相当于多重集的排列,答案即为:\(\frac{n-2}{\prod deg_i-1}\)


CF156D Clues

设每个连通块点的个数为 \(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\)


P5454 [THUPC2018]城市地铁规划

可以看做背包模型,将每个点看做价值为 \(f(deg_i)\),体积为 \(deg_i-1\) 的物品去填充体积为 \(n-2\) 的背包

背包过程中可以顺便记录转移,之后用 \(prufer\) 将序列转化成树

posted @ 2021-11-16 21:46  y_cx  阅读(84)  评论(1编辑  收藏  举报