Prufer 序列 学习笔记
定义
Prufer 序列的定义:
对于一个有根树,每次选择编号最小的叶子节点删掉,然后记录他的父亲,直到剩下两个节点,形成一个 长度的序列。
可以证明这个序列和一个 个节点的无根树一一对应。同时也可以证明一个 个节点完全图的生成树数量为 。
由树构造 Prufer 序列
显然用堆可以 。
发现如果一个节点删除之后,如果他的父亲成为了新的叶子节点,并且编号比删除的节点小,那么接下来删除的肯定是他的父亲(因为其他的节点编号都比删除的节点大。这样就线性了。。
由 Prufer 序列构造树
根据 Prufer 序列可以得到树的度数。用堆依旧是 。
考虑模仿树构造 Prufer 序列,如果序列中后一个数字比前一个数字更小,那么肯定就是父子关系,否则继续找最小的度数是 的节点,同样是线性的。
int n,opt,fa[maxn],p[maxn],d[maxn]; void S1(){//tree -> prufer int i,j; ll ans=0; for(i=1;i<n;i++) fa[i]=read(),d[fa[i]]++; for(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++; } for(i=1;i<=n-2;i++) ans^=1ll*i*p[i]; print(ans); return; } void S2(){//prufer -> tree int i,j; ll ans=0; for(i=1;i<=n-2;i++) p[i]=read(),d[p[i]]++; p[n-1]=n; for(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++; } for(i=1;i<n;i++) ans^=1ll*i*fa[i]; print(ans); return; } int main(){ freopen("1.in","r",stdin); //freopen(".out","w",stdout); n=read(); opt=read(); if(opt==1) S1(); else S2(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具