prufer序


prufer 序

P6086 【模板】Prufer 序列

$prufer$ 序列可以将一个带标号 $n$ 个结点的树用 $[1,n]$ 中的 $n-2$ 个整数表示。或者可以说,一个 $prufer$ 序对应一个无根树。

$prufer$ 构造方式:每回将编号最小的叶节点删掉,记录连接它的唯一节点,最后就剩两个节点就结束操作。得到的记录的数列就是 $prufer$ 序列。一个简单的图示:

prufer序

我们根据它的构造原理,很简单就能搞明白为什么会有唯一对应关系

$prufer$ 序列的性质:

  • 在构造完 $prufer$ 序列后原树中会剩下两个结点,其中一个一定是编号最大的点 。

  • 每个结点在序列中出现的次数是其度数减 $1$。(没有出现的就是叶结点)

思路

在这到题目中,规定了根节点 $n$,这样,在父节点确定时,$prufer$ 序是唯一的,我们已经知道了每个点的父节点,或者 $prufer$ 序,即让我们无根树和 $prufer$ 序相互转换。由于结果已经知道是唯一的,所以只要知道构造方法就可以得出结果。

互相转换的关键在于,$pruerl$ 构造原理:每回都是将最小节点除去,记录它的唯一连接节点。

细节就看代码吧。

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
long long r_r(){//快读 
	long long x=0,f=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(isdigit(c)){
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return x*f;
}
const int o_o=1e7+10;
int n;
int f_f[o_o];//父数组 
int p_p[o_o];//prufer 序 
int s_s[o_o];//统计节点出现的次数 
long long a_s;
void f_p(){//有根树转 prufer 序列 
	for(int i=1;i<n;i++){
		f_f[i]=r_r();//读入序列 
		++s_s[f_f[i]];//(父)节点的度加 1  
	}
	for(int i=1,j=1;i<=n-2;i++,j++){
		while(s_s[j])++j;//找编号最小的节点 
		p_p[i]=f_f[j];//加入 prufer 序列 
		while(i<=n-2&&!--s_s[p_p[i]]&&p_p[i]<j){
			p_p[i+1]=f_f[p_p[i]];//父节点小,加入 prufer 序列。 
			++i;
		}
	}
	for(int i=1;i<=n-2;i++)a_s^=1ll*i*p_p[i];//统计权值 
}
void s_p(){//prufer 序列转有根树 
	for(int i=1;i<=n-2;i++){
		p_p[i]=r_r();//读入序列 
		++s_s[p_p[i]];//(父)节点深度加一 
	}
	p_p[n-1]=n;//题目中说读入将 n 设为根,最后一定的 prufer 一定是 n。  
	for(int i=1,j=1;i<n;i++,j++){
		while(s_s[j])++j;//找编号最小的节点 
		f_f[j]=p_p[i];//加入父序列 
		while(i<n&&!--s_s[p_p[i]]&&p_p[i]<j){
			f_f[p_p[i]]=p_p[i+1];//父节点小,加入父序列 
			++i;
		}
	}
	for(int i=1;i<n;i++)a_s^=1ll*i*f_f[i];//统计权值 
}
int main(){
	n=r_r();//读入树的点数 
	int op=r_r();//转化类型 
	if(op==1)f_p();//父亲序列 
	else s_p();//prufer 序列 
	printf("%lld",a_s);//输出结果 
	return 0;
}

补充

  • 如果题目中没有规定 $n$ 为根节点,也没有规定父子节点关系,有多少种 $prufer$ 序?

这就是 $Cayley$ 公式。

若该完全图有 $n$ 个节点,则任意一个长度为 $n-2$ 的 $prufer$ 序列都可以重构出其一棵生成树,且各不相同。又因为 $prufer$ 序列的值域在 $[1,n]$ ,所以总共有 $n^{n-2}$ 种情况。

  • 有 $n$ 个点,能组成多少个有根树?

和无根树不同出在于根节点不同,一共有 $n\times n^{n-2}=n^{n-1}$ 种情况。

我们知道每个点的度数和在 $prufer$ 序中出现的次数关系有关:

  • 给定 $n$ 个点,每个点的度数为 $d_i$,无根树有多少种?

因为 $prefur$ 序的长度 $n-2$ 则有 $(n-2)!$ 中排法,其中每个点又会出现重复的贡献 $(d_i-1)!$ 次。

所以最后一共有:

种结果。


文章作者: 王大神——A001
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 王大神——A001 !
  目录