P6086 【模板】Prufer 序列
前言:
\(prufer\)序列常用于树的计数问题,一些常用的性质:
1.度数为\(d\)的点,在\(prufer\)序列出现的次数为\(d-1\)次。
2.对于完全图的生成树为\(n^{n-2}\)
题意:
两种操作:
\(1.给定一棵树转换成prufer序列。\)
\(2.给定prufer序列重构一棵树。\)
题解:
1.如何把一颗树转换成\(prufer\)序列?
一棵树有着唯一的\(prufer\)序列与之对应,\(n\)个节点的树,\(prufer\)序列的长度为\(n-2\),重复两个步骤:1.找出最小编号的度数为\(1\)的节点将它的父亲节点放入\(prufer\)序列中。2.将该节点删除。重复这两个步骤,直到这棵树只剩下两个节点,此时的序列就是\(prufer\)序列。这个过程有两种写法:
(1).用小根堆维护度数为\(1\)的节点的编号,如果一个点的父亲节点度数为\(1\),则扔进堆里面,时间复杂度\(O(nlogn)\)。
(2).线性维护:先找出节点中序号最小的且度数为\(1\)的节点,从这个节点开始,如果他的父亲节点为\(1\)过后,且该节点的父亲节点的编号小于当前节点,那么就从该节点开始继续否则,按照顺序继续找。时间复杂度\(O(n)\)。
for(int i=1;i<n;i++) scanf("%d",&f[i]);
for(int i=1;i<=n;i++) de[i]++;
for(int i=1;i<n;i++) de[f[i]]++;
for(int i=1;i<=n;i++)
if(de[i]==1){pos=i;break;}
leaf=pos;
while(cnt<n-2){
int tmp=f[leaf];
de[tmp]--;p[++cnt]=tmp;
if(de[tmp]==1&&tmp<pos){
leaf=tmp;
}else{
pos++;
while(de[pos]!=1) pos++;
leaf=pos;
}
}
2.如何将\(prufer\)序列重构成一棵树?
借鉴前面的方法,先算出每个节点的度数,同样先找出节点编号最小的度数为\(1\)的点,该点的父亲节点是\(prufer\)的第一个点,如果度数为\(1\),那么父亲的父亲就是第二个点,否则继续找下一个度数为1的编号,继续就可以了。
for(int i=1;i<=n-2;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) de[i]=1;
for(int i=1;i<=n-2;i++) de[p[i]]++;
for(int i=1;i<=n;i++){
if(de[i]==1){
pos=i;break;
}
}
leaf=pos;
while(cnt<n-2){
int fa;
fa=f[leaf]=p[++cnt];
de[fa]--;
if(de[fa]==1&&fa<pos) leaf=fa;
else{
pos++;
while(de[pos]!=1) pos++;
leaf=pos;
}
}
f[leaf]=n;
最后的代码:
#include "bits/stdc++.h"
using namespace std;
const int N=5e6+5;
int n,m,cnt,pos,leaf,f[N],p[N],de[N];
long long ans;
void solve1(){
for(int i=1;i<n;i++) scanf("%d",&f[i]);
for(int i=1;i<=n;i++) de[i]++;
for(int i=1;i<n;i++) de[f[i]]++;
for(int i=1;i<=n;i++)
if(de[i]==1){pos=i;break;}
leaf=pos;
while(cnt<n-2){
int tmp=f[leaf];
de[tmp]--;p[++cnt]=tmp;
if(de[tmp]==1&&tmp<pos){
leaf=tmp;
}else{
pos++;
while(de[pos]!=1) pos++;
leaf=pos;
}
}
for(int i=1;i<=cnt;i++) ans^=1ll*i*p[i];
printf("%lld",ans);
}
void solve2(){
for(int i=1;i<=n-2;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) de[i]=1;
for(int i=1;i<=n-2;i++) de[p[i]]++;
for(int i=1;i<=n;i++){
if(de[i]==1){
pos=i;break;
}
}
leaf=pos;
while(cnt<n-2){
int fa;
fa=f[leaf]=p[++cnt];
de[fa]--;
if(de[fa]==1&&fa<pos) leaf=fa;
else{
pos++;
while(de[pos]!=1) pos++;
leaf=pos;
}
}
f[leaf]=n;
for(int i=1;i<=n;i++) ans^=1ll*i*f[i];
printf("%lld",ans);
}
int main(){
scanf("%d %d",&n,&m);
if(m==1) solve1();
if(m==2) solve2();
return 0;
}
要拿牌啊

浙公网安备 33010602011771号