下笔春蚕食叶声。

Prufer序列

Prufer 序列

作用

将带标号 \(n\) 节点树用 \(n-2\)\([1,n]\) 的整数表示,

\(n\) 个点的完全图的生成树和长度为 \(n-2\) 的值域为 \([1,n]\) 的数列构成的双射。

Cayley 定理,\(n\) 个点有标号生成树共 \(n^{n-2}\) 个。Anne's game

算法

树转 Prufer 序列

每次选择一个编号最小的叶节点删除,记录它的父亲。

重复 \(n-2\) 次以后剩下两个节点,算法结束。

堆:\(O(n\log n)\)

指针:\(O(n)\)

指针指向编号最小的叶节点,每次删掉以后,

  • 如果产生了新的叶节点,且编号比已经填写完的更小,就直接继续删掉

  • 否则++,找到下一个编号最小的叶节点。

Prufer 序列转树

可以得到原树上每个点的度数。

每次选择一个编号最小的度数为1的节点,与当前枚举的Prufer序列的点连接,然后同时减掉两个点的度数,重复 \(n-2\) 次后剩下两个度数为1的点,其中一个是 \(n\) ,连接他们即可。

堆: \(O(n\log n)\)

指针:\(O(n)\)

具体而言,指针指向编号最小的度数为 1 的节点。

每次将它与当前枚举到的 Prufer 序列的点连接之后,

  • 如果产生了新的度数为 1 的节点且编号比当前处理“完”的更小,则直接继续将它与下一个 Prufer 序列的点连接,
  • 否则++,找到下一个编号最小的度数为 1 的节点。

实现

【模板】Prufer 序列

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define pb push_back
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define ls(x) ((x) << 1)
#define rs(x) ((x) << 1 | 1)
#define fi first
#define se second
const int N = 5e6 + 10;
int n, m, fa[N], p[N], d[N];
void tree_prufer() {
	for(int i = 1; i < n; i++)
		scanf("%d", &fa[i]), d[fa[i]]++;
	for(int i = 1, j = 1; i <= n - 2; i++, j++) {
		while(d[j]) j++; p[i] = fa[j];
		while(i <= n - 2 && !(--d[p[i]]) && p[i] < j)
			p[i + 1] = fa[p[i]], i++;
	}
	ll ans = 0;
	for(int i = 1; i <= n - 2; i++)
		ans ^= (1ll * i * p[i]);
	printf("%lld\n", ans);
	return;
}
void prufer_tree() {
	for(int i = 1; i <= n - 2; i++)
		scanf("%d", &p[i]), d[p[i]]++;
	p[n - 1] = n; d[n]++;
	for(int i = 1, j = 1; i < n; i++, j++) {
		while(d[j]) j++; fa[j] = p[i];
		while(i < n && !(--d[p[i]]) && p[i] < j)
			fa[p[i]] = p[i + 1], i++;
	}
	ll ans = 0;
	for(int i = 1; i < n; i++)
		ans ^= (1ll * i * fa[i]);
	printf("%lld\n", ans);
	return;
}
int main(){
	scanf("%d%d", &n, &m);
	if(m == 1) tree_prufer();
	else prufer_tree();
	return 0;
}

一些结论:

  • 给定所有点度数的有标号无根树个数:\(\frac {(n-2)!} {(d_i-1)!}\)
  • \(k\) 个给定的联通块,加 \(k-1\) 条边使得其成为一棵树: \(n^{k-2} \prod {sz_i}\)
    证明:
    考虑确定度数的,是 \(\sum_{d_i > 0,\sum d_i = 2(k-1)} \frac {(n-2)!} {(d_i-1)!}\prod {sz_i}^{d_i}\)
    \(\sum_{d_i-1\ge 0,\sum (d_i-1) = k-2} \frac {(n-2)!} {(d_i-1)!}\prod {sz_i}^{(d_i-1)+1}\)
    考虑多元二项式定理 \((\sum_{i=1}^m x_i)^p = \sum_{c_i \ge 0,\sum_{i=1}^m c_i=p} \frac {p!} {\prod (c_i)!}\prod_{i=1}^m {x_i}^{c_i}\)
    所以是 \(n^{k-2} \prod {sz_i}\)
posted @ 2021-01-27 14:47  ACwisher  阅读(76)  评论(0编辑  收藏  举报