prufer序列

prufer序列是一种树形结构和数列相互映射的规则

与其他序列的区别

dfs序,将一棵子树映射为一段连续的区间
二叉搜索树,中序遍历是单调不减的序列
prufer序列:

  • 1.是一个和树的双射,唯一对应一棵树
  • 2.包含结点的度数和连接关系

使用场景

将构造树转化为构造序列,将统计树转化为统计序列,将树的dp转化为数列的dp

如何得到prufer序列

  • 1.统计树上所有结点的度数degree[i]
  • 2.找到所有度数为1的结点中编号最小的那个结点cur
  • 3.令p[i]=fa[cur],同时将degree[fa[cur]]--
  • 4.重复步骤2-3,直到剩余两个点时结束

性质

  • 1.结点x在prufer序列中出现的次数+1就是degree[x]
  • 2.编号最大的点n绝对是剩下的2个结点之一

因此一般把n当作根节点,这样不会删掉根节点

P6086 【模板】Prufer 序列

#include<bits/stdc++.h>
#define int long long
using namespace std;
int pre[5000010];
int fa[5000010];
int deg[5000010];
int n,m;
int ans;

void prufer(){
	int cur;//fa为父亲序列 
	for(int i=1;i<=n;i++){
		if(deg[i]==1){
			cur=i;//最小的度数为1的点 
			break;
		}
	}
	int leaf=cur;
	for(int i=1;i<=n-2;i++){
		//cout<<leaf<<endl;
		ans=ans^(i*fa[leaf]);
		deg[fa[leaf]]--;
		if(deg[fa[leaf]]==1 && fa[leaf]<cur){
			leaf=fa[leaf];
			continue;
		}
		else{
			cur++;
			while(deg[cur]!=1){
				cur++;
			}
			leaf=cur;
		}
	}
	cout<<ans;
}

void pre_tree(){
	for(int i=1;i<=n;i++) deg[i]=1;
	int cur,leaf;
	for(int i=1;i<=n-2;i++) deg[pre[i]]++;
	for(int i=1;i<=n;i++){
		if(deg[i]==1){
			cur=i;
			break;
		}
	}
	leaf=cur;
	for(int i=1;i<=n-2;i++){
		int f=fa[leaf]=pre[i];
		deg[f]--;
		if(deg[f]==1 && f<cur){
			leaf=f;
			continue;
		}
		else{
			cur++;
			while(deg[cur]!=1){
				cur++;
			}
			leaf=cur;
		}
	}
	fa[leaf]=n;
	for(int i=1;i<n;i++) ans=ans^(fa[i]*i);
	cout<<ans;
}

signed main(){
	cin>>n>>m;
	if(m==1){
		for(int i=1;i<n;i++){
			cin>>fa[i];
			deg[i]++;
			deg[fa[i]]++;
		}
		//for(int i=1;i<=n;i++) cout<<deg[i]<<endl;
		prufer();
	}
	else{
		for(int i=1;i<n-1;i++){
			cin>>pre[i];
		}
		pre_tree();
	}	
	return 0;
}

P5454 [THUPC2018] 城市地铁规划

观察题目的便利度计算公式,发现这个东西显然是可以预处理的,而f(x)的参数x显然是点x的度数。

题目中说:
新建的地铁轨道尽可能少,但任意两座地标之间都需要能通过地铁相互到达。
其实就是一棵树,那么度数总和就是2n-2,于是可以对于度数完全背包(注意每一个点都必须有度数),并且在做完全背包的过程中记录上一个状态,以便得到每一个点的度数。

得到度数用prufer构造成树就行了(其他复杂度更高的方法也是可以的,瓶颈在完全背包);

常用性质

  • 1.对于n个点的完全图,其生成树的方案数为\(n^{n-2}\)
  • 2.对于n个点的无根树,其树的方案数为\(n^{n-2}\)
  • 3.对于n个点的有根树,其树的方案数为\(n^{n-1}\)
    前面三个都挺显然的
  • 4.对于n个节点,约定点i的度数为d[i],满足条件的树的方案数为\(\frac{(n-2)!}{\prod_{i=1}^{n}(d_i-1)!}\)

P2624 [HNOI2008] 明明的烦恼

从prufer序列的角度:
设有x个点确定了度数d[i],还剩n-x个点待确定
还有n-2-x个数需要出现,在n-x个点中选取

posted @ 2024-02-21 14:44  星河倒注  阅读(123)  评论(0)    收藏  举报