题目链接:Problem - 1336A - Codeforcest
题意:给定一棵树,选择k个点,求每个点到根(1是根节点)之间最短路径上非选择点数量之和的最大值。
对于任意一个父节点,我们如果选择父节点而不选择他的子节点,那么一定不如选择他的子节点,可以得到更大的数。
根据我们得出的结论,来计算每个节点对答案的贡献。对于一棵树,我们先考虑每个节点对他的贡献。首先,这个节点对答案的正贡献是到根节点的距离deep,因为我们选择一个节点就一定会选择他的子节点,所以选择这个点会让他所有的子孙节点的贡献-1,所以负贡献为s[i](s数组表示该节点子孙节点的数量),总的贡献就是 deep - s[i] ,将每个点的贡献排序,从大到小选择k个,即为最大值。
#include
#define int long long
using namespace std;
const int N = 200010 , M = N * 2 ;
int n , m ;
int h[N] , e[M] , ne[M] , idx ;
int s[N] ;
vector res ;
void add(int a , int b)
{
e[idx] = b , ne[idx] = h[a] , h[a] = idx ++ ;
}
void dfs(int u , int fa , int deep)
{
int c = 0 ;
for(int i = h[u] ; ~i ; i = ne[i])
{
int j = e[i] ;
if(j == fa) continue ;
c ++ ;
dfs(j , u , deep + 1) ;
s[u] += s[j] ;
}
s[u] += c ;
res.push_back(deep - s[u]) ;
}
signed main()
{
cin >> n >> m ;
memset(h , -1 , sizeof h) ;
for(int i = 1 ; i <= n - 1 ; i ++)
{
int a , b ;
scanf("%lld%lld",&a,&b) ;
add(a , b) , add(b , a) ;
}
dfs(1 , -1 , 0) ;
int sum = 0 ;
sort(res.begin() , res.end()) ;
reverse(res.begin() , res.end()) ;
for(int i = 0 ; i < m ; i ++)
sum += res[i] ;
cout << sum << endl ;
return 0 ;
}