[CF1042F]Leaf Sets
Posted slrslr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1042F]Leaf Sets相关的知识,希望对你有一定的参考价值。
题意:给定一棵$n$个点的树,将叶子节点分为数个集合使集合里点对最长距离不超过$k$,求最少集合数。($nle1000000$)
首先我们可以想到,这道题并不是让你构造最优方案,因为只要把所有叶子节点的集合任意合并至无法操作,就一定是最优答案了
这个感性理解一下就是那么回事,我一开始做的时候就想到的
然后其实我们把叶子结点向上合并即可,只要子树内两个集合的距离不超过$k$,就把他们合起来,记成到当前点距离较大的那个集合
这样对于子树两两合并,我们可以用启发式合并的堆来实现,复杂度是$nlog^2n$,并不足以通过这道题
再想想看,其实如果一个集合和当前最小的集合已经无法合并了,就不用再往上推了,因为上边的集合的最远点只会更远,所以把这个集合留住在这,答案加一
然后我们可以把子树内两个集合的距离不超过$k$的集合合并起来,这样我们每次向上传递的只有一个集合了,复杂度$nlogn$
就从一道大数据结构题变成了一道思维难度更大的题了
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #define M 1000010 5 using namespace std; 6 int read() 7 { 8 char ch=getchar();int x=0; 9 while(ch>‘9‘||ch<‘0‘) ch=getchar(); 10 while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); 11 return x; 12 } 13 int n,num,ans,k; 14 int head[M],in[M]; 15 struct point{int to,next;}e[M<<1]; 16 void add(int from,int to) 17 { 18 e[++num].next=head[from]; 19 e[num].to=to; 20 head[from]=num; 21 } 22 int dfs(int x,int fa) 23 { 24 if(in[x]==1) return 0; 25 priority_queue<int>q; 26 for(int i=head[x];i;i=e[i].next) 27 { 28 int to=e[i].to; 29 if(to==fa) continue; 30 q.push(dfs(to,x)+1); 31 } 32 int maxn=q.top();q.pop(); 33 while(!q.empty()) 34 { 35 if(q.top()+maxn<=k) return maxn; 36 ans++; 37 maxn=q.top(); 38 q.pop(); 39 } 40 return maxn; 41 } 42 int main() 43 { 44 n=read(); k=read(); 45 for(int i=1;i<n;i++) 46 { 47 int a=read(),b=read(); 48 add(a,b); add(b,a); 49 in[a]++; in[b]++; 50 } 51 for(int i=1;i<=n;i++) if(in[i]!=1){dfs(i,0);break;} 52 printf("%d",ans+1); 53 return 0; 54 }
以上是关于[CF1042F]Leaf Sets的主要内容,如果未能解决你的问题,请参考以下文章