Prufer 序列

6 篇文章 0 订阅
1 篇文章 0 订阅

其实这个没什么好说的啦。。。就相当于一种很妙的树hash
好像在NOIWC有出过。。。

就是这个是个双射,且一一对应

就每次找编号最小的叶子节点,删掉,迭代至只剩一个点

也可以从prufer变为原树
注意,以某个点为根,要在最后一位添一位,并且那个根不能找父亲。。。

O ( n l o g n ) O(nlogn) Onlogn
左右。。
还有一个 O ( n ) O(n) O(n)的假做法,但可能会被卡成 O ( n 2 ) O(n^2) O(n2)。。。。
你想看可以去洛谷找。。。
不然我贴个连接

#include<bits/stdc++.h>
#define MAXN 5000005
typedef long long ll;
using namespace std;

ll n,m,tot,ans = 0;
ll in[MAXN],fa[MAXN],g[MAXN],prufer[MAXN];

struct node{
	ll id;
	friend bool operator < (node x , node y){
		return x.id > y.id;
	}
};
priority_queue<node>q;
set<ll>num;

int main(){
	cin>>n>>m;memset(in , 0 , sizeof(in));
	if(m == 1){
		for(int i = 1 ; i < n ; i++)scanf("%d" , &fa[i]) , in[fa[i]]++;
		for(int i = 1 ; i <= n ; i++){
			if(!in[i])q.push((node){i});
		}
		for(int i = 1 ; i <= n - 2 ; i++){
			ll now = q.top().id;q.pop();
			g[i] = fa[now];
			in[fa[now]]--;
			if(!in[fa[now]])q.push((node){fa[now]});
			ans = ans ^ (i * g[i]);
		}
		cout<<ans<<endl;
		exit(0);
	}
	else{
		for(int i = 1 ; i <= n - 2 ; i++)scanf("%d" , &prufer[i]) , in[prufer[i]]++;
		prufer[n - 1] = n;
		for(int i = 1 ; i < n ; i++)if(!in[i])num.insert(i);
		for(int i = 1 ; i < n ; i++){
			ll zz = *num.begin();
			num.erase(zz);
			fa[zz] = prufer[i];
			in[prufer[i]]--;
			if(!in[prufer[i]] && prufer[i] != n)num.insert(prufer[i]);
		}
		for(int i = 1 ; i < n ; i++)ans = ans ^ (i * fa[i]);
		cout<<ans<<endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值