AT2293-[AGC009D] Uninity【贪心,状压】

1|0正题

题目链接:https://www.luogu.com.cn/problem/AT2293


1|1题目大意

给出一棵树,求它一棵点分树的最小深度。

1n105


1|2解题思路

点分树的做法是直接找重心,但是两个重心我们很难确定找哪个,所以这个方法行不通。

但是这样我们大概能确定答案的上界是logn级别的。考虑我们记每个点的点分子树深度di,那么di肯定满足对于一对深度相同的(x,y),它们的路径上肯定存在一个点z满足dz>dx,dz>dy

那么同样的,如果我们得到一个满足这个条件的数组d,我们也能构造出一棵合法的点分树,所以我们的目的就是要最小化d的值。

考虑一个构造方法,对于一个节点x的深度p,首先如果它的儿子中有深度为p的点那么显然不合法,如果存在一个在它不同子树中的节点y的深度p,并且xy路径上节点深度都不超过p,那么显然也不合法。

显然上面这两个条件我们可以用状压搞定。

但是这样构造为什么是合法的呢?我也不知道,只能感性证明一下。能发现我们的操作中如果一个节点x选择了深度p,那么它往上的限制中所有深度<p的限制都会被打开,也就是说实际上选择更大的深度并不会放松后面的限制,所以选最小的更优。

时间复杂度:O(nlogn)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+10; struct node{ int to,next; }a[N<<1]; int n,tot,ls[N],f[N],ans; void addl(int x,int y){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;return; } void dfs(int x,int fa){ int p=0,s=0; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(y==fa)continue; dfs(y,x); for(int j=30;j>=0;j--) if(s&f[y]&(1<<j)) {p=max(p,j+1);break;} s|=f[y]; } while((s>>p)&1)p++; ans=max(ans,p); f[x]=s|((1<<p+1)-1); f[x]=f[x]^((1<<p)-1); return; } int main() { scanf("%d",&n); for(int i=1,x,y;i<n;i++){ scanf("%d%d",&x,&y); addl(x,y);addl(y,x); } dfs(1,0); printf("%d\n",ans); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16221509.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(84)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-05-04 P7581-「RdOI R2」路径权值【长链剖分,dp】
2021-05-04 P4922-[MtOI2018]崩坏3?非酋之战!【dp】
点击右上角即可分享
微信分享提示