CF1042F Leaf Sets(题解)

F. Leaf Sets

给定一棵n个点的树,将叶子节点分为数个集合使集合里点对最长距离不超过k,求最少集合数。

 

 

You are given an undirected tree, consisting of n vertices.

The vertex is called a leaf if it has exactly one vertex adjacent to it.

The distance between some pair of vertices is the number of edges in the shortest path between them.

Let's call some set of leaves beautiful if the maximum distance between any pair of leaves in it is less or equal to kk.

You want to split all leaves into non-intersecting beautiful sets. What is the minimal number of sets in such a split?

Input

The first line contains two integers nn and kk (3n1e6,1≤k≤1e6) — the number of vertices in the tree and the maximum distance between any pair of leaves in each beautiful set.

Each of the next n1n−1 lines contains two integers vivi and uiui (1vi,uin1≤vi,ui≤n) — the description of the ii-th edge.

It is guaranteed that the given edges form a tree.

Output

Print a single integer — the minimal number of beautiful sets the split can have.

Examples
input
9 3
1 2
1 3
2 4
2 5
3 6
6 7
6 8
3 9
output
2
input
5 3
1 2
2 3
3 4
4 5
output
2
input
6 1
1 2
1 3
1 4
1 5
1 6
output
5
Note

Here is the graph for the first example:

题解:这道题的题意比较清晰,就不多解释啦。

对于关于树的问题,有一个很常见的方法:找到一个非叶子节点作为根,然后一边dfs一边处理子树中的问题,一路合并上去。

若a,b为节点x的儿子,我们假设d_a为以a为根的子树中与a最远的叶子与a的距离(也就是以a为根的子树的深度),d_b同理。

在判断a、b能否合并时,我们只需要判断da+db+2<=k是否成立即可。假如我们知道x所有儿子的d值,就可以贪心地合并啦-v-

设x儿子d值的集合(允许重复)为A,如果A中任意两个元素的和都<=k那么答案不会增加,因为没有无法融合的集合。

但是如果有>k的怎么办?为了解决这个问题,我们需要对A排序,设A中最大元素为d_max1,第二大元素为d_max2,d_max2<=d_max1,

如果d_max1+d_max2+2>k,说明这两个元素对应子树中的叶子不能放在一个集合里,于是把d_max1从A中删除,ans++。

为了方便地求出A集合,在dfs时返回删完之后A集合中的最大值就行。

时间复杂度O(nlogn):对每个节点的所有儿子一遍排序,1e6可能会卡,但是这道题开了3s,欸嘿嘿~

 

这里是代码↓

 

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 #define maxn 1000010
 5 using namespace std;
 6 bool vis[maxn];
 7 int n,k,u,v,ans;
 8 vector<int> ve[maxn];
 9 void add(int x,int y){ve[x].push_back(y);}
10 int dfs(int x){
11     vis[x]=1;
12     if(ve[x].size()==1) return 0;
13     vector<int> tmp;
14     for(int i=0;i<ve[x].size();i++){
15         int v=ve[x][i];
16         if(!vis[v]) tmp.push_back(dfs(v)+1);
17     }
18     sort(tmp.begin(),tmp.end());
19     while(tmp.size()>1){
20         int sz=tmp.size();
21         if(tmp[sz-1]+tmp[sz-2]<=k) break;
22         ans++,tmp.pop_back();
23     }
24     return tmp.back();
25 }
26 int main(){
27     scanf("%d%d",&n,&k);
28     for(int i=1;i<n;i++)scanf("%d%d",&u,&v),add(u,v),add(v,u);
29     for(int i=1;i<=n;i++)if(ve[i].size()>1){dfs(i);break;}
30     printf("%d\n",ans+1);
31     return 0;
32 }

 

 

 

转载于:https://www.cnblogs.com/al76/p/9696542.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值