[codeforces] 1399 E1. Weights Division (easy version)

题目链接
题目大意:
求由所有根节点到树叶节点带权路径之和,要求经过不断地对某个路径/2,使总和<=给定S,求对路径权重/2的次数。
解题思路:
一条边可能是n个根节点到叶节点的路径的边,此时它对sum的贡献是n*w,我们不能简单根据贡献选取边进行除2,考虑w = 7,n = 7,和w = 10,n =5,此时对sum的cost分别为28和25,因此,我们应该选取对sum cost最大的边进行操作。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fi first
int t,n;
typedef long long ll;
ll sum = 0,S;
const int N = 1e5+5;
vector<pair<int,int> > g[N];
struct pp{
    
    
	ll w;
	ll cnt;
	pp(ll _w,ll _cnt):w(_w),cnt(_cnt){
    
    
	}
	bool operator<(const pp& x)const{
    
    
	 	ll cost =(w -w / 2) *cnt;
		ll x_cost = x.cnt *(x.w - x.w / 2);
		return cost <x_cost; 
	}
};
priority_queue<pp> q;
ll dfs(int x,int pre){
    
    
	ll s = 0;
	if(x != 1 && g[x].size() == 1){
    
    	
		return 1;
	}
	for(int i = 0;i<g[x].size();i++){
    
    
		pair<int,int> p = g[x][i];
		int v = p.fi,w = p.se;
		if(v == pre)
			continue;
		ll ts = dfs(v,x);
		sum += w *ts;
		q.push(pp(w,ts));
		s += ts; 
	}
	return s;
}

int main(){
    
    
	int t;
	scanf("%d",&t);
	while(t--){
    
    
		sum = 0;
		while(!q.empty())q.pop();
		scanf("%d%lld",&n,&S);
	
		for(int i = 1;i <= n;i++)
			g[i].clear();
		for(int i = 1;i <= n-1;i++){
    
    
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
		
			g[u].pb(mp(v,w));
			g[v].pb(mp(u,w));

		}
		dfs(1,-1);
		ll mv = 0;
		while(sum>S){
    
    
			pp x = q.top();
			q.pop();
			sum -= x.cnt *(x.w - x.w / 2);
			q.push(pp(x.w / 2,x.cnt));
			mv++;
		}
		printf("%lld\n",mv);	
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_20252251/article/details/108118578