2021百度之星复赛03 Subtraction (贪心)

请添加图片描述

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int b[N], p[N];
vector<int>g[N];
ll ans, bas;
int n;

int dfs(int u, int fa) {
    
    
	vector<int>vec;//储存儿子节点最多可以被合并多少步
	for (auto i : g[u]) {
    
    
		if (i != fa) {
    
    
			vec.push_back(dfs(i, u));
		}
	}
	ll sum = 0; //储存在不考虑p的情况下,最多能合并所有儿子多少操作
	for (auto i : vec) {
    
    
		sum += min(b[u], i); //合并操作数量不能多于u点本身
	}
	if (sum >= (ll)b[u]*p[u]) {
    
     //如果所有儿子可合并的操作超过u点本身(b[u]*p[u])
		ans += (ll)b[u] * p[u]; //只能取u点本身的极限
		return 0;//而且不能再被u点的父亲扩展,返回值为0
	}
	ans += sum; //否者就将所有儿子的合并加到ans
	return min((ll)b[u] * p[u] - sum, (ll)b[u]);
}

void slove() {
    
    
	cin >> n;
	ans = bas = 0;
	for (int i = 1; i <= n; i++)
		g[i].clear();
	for (int i = 1; i < n; i++) {
    
    
		int a, b;
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	for (int i = 1; i <= n; i++) {
    
    
		cin >> b[i] >> p[i];
		bas += b[i]; //如果使用暴力,需要多少步
	}
	dfs(1, 0);
	cout << bas - ans << endl; //ans就是可以优化的步数

}

int main() {
    
    
	ios;
	int t;
	cin >> t;
	while (t--) {
    
    
		slove();
	}
}

猜你喜欢

转载自blog.csdn.net/fdxgcw/article/details/119862550
今日推荐