Codeforces Round #635 (Div. 2) C. Linova and Kingdom

这题真的忐忑,首先读完题目第一反应就是直接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;
}
原创文章 93 获赞 12 访问量 8981

猜你喜欢

转载自blog.csdn.net/weixin_43571920/article/details/105583116