这题真的忐忑,首先读完题目第一反应就是直接dfs一遍,求一个深度,选深度最深的k个,结果题目要求是经过旅游景点,然后发现这不可行,然后想了一种贪心思路,按dep从大大小排序,然后dep相等在按直接儿子个数从小到大排序,因为儿子越多的,选了它就会对选的dep更深选的影响越大,然后排完序依次选,答案就是dep - siz + 1,写了一发,交上去wa5,因为假设节点 u 的dep比较大,但是他的子孙也很多,另一个节点 v 的 dep 比它小的,但是是叶子节点,dep[u] - siz[u] + 1 < dep[v] - siz[v] + 1,所以就导致答案错误了。最后应该按照拓扑排序那样依次选取叶子节点,依次放进优先队列里,依次选取k个就好了,但注意,这里1节点初始不能放进去,因为它不能被选,就是因为这个最终被hack!
还有种做法就是直接对每个节点的dep[u] - siz[u] + 1从大排序,答案就依次选k个。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
typedef long long ll;
const ll mod = 1e9+7;
vector<int>sp[man];
int du[man],fa[man],dep[man],num[man];
struct node{
int v,dep;
bool operator < (const node &a)const{
return dep < a.dep;
}
};
priority_queue<node>q;
void dfs(int u,int f,int dp){
dep[u] = dp;
num[u] = 1;
fa[u] = f;
int cnt = 0;
for(int i = 0;i < sp[u].size();i++){
int v = sp[u][i];
if(v==f)continue;
dfs(v,u,dp+1);
cnt++;
num[u] += num[v];
}
du[u] = cnt;
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int n,k;
cin >> n >> k;
for(int i = 1;i < n;i++){
int u,v;
cin >> u >> v;
sp[u].push_back(v);
sp[v].push_back(u);
}
dfs(1,0,0);
for(int i = 1;i <= n;i++){
if(du[i]==0)q.push(node{i,dep[i]});
}
ll ans = 0;
for(int i = 1;i <= k;i++){
node tp = q.top();
q.pop();
ans += tp.dep;
du[fa[tp.v]]--;
if(du[fa[tp.v]]==0){
q.push(node{fa[tp.v],dep[fa[tp.v]] - (num[fa[tp.v]] - 1)});
}
}
cout << ans << endl;
return 0;
}