璟雯院

珺璟如晔,雯华若锦

用户工具

站点工具


icpc:problems:usaco22dec_barn_tree_s
problems
名称Barn Tree S
题目编号USACO22DEC_S1
题目链接luogu.com.cn/…
来源USACO
算法分类DFS, 树型结构
难易程度容易

Barn Tree S

想法

对于任意根结点,先处理干草多的子树,将多余的子树移动至根,再处理干草少的子树,将少的干草从根移动至子树。

由于题目给的为树,且任意两点间的路径只有一条,故按照此方式来是最少的放置方案。

代码实现

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
 
const int N = 2*1e5 + 10;
struct node{
	long long int v;
	int next;
};
struct ansNode{
	int x, y;
	long long int v;
};
vector<ansNode>ans;
node edge[2*N];
int n, head[N], cnt;
long long int h[N], sum[N], num[N], aim;
 
void add_edge(int x, int y){
	edge[++cnt].v = y;
	edge[cnt].next = head[x];
	head[x] = cnt;
	return ;
}
 
void build(int x, int f){
	num[x] = 1; sum[x] = h[x];
	for(int i=head[x]; ~i; i=edge[i].next){
		int v = edge[i].v;
		if(v == f)continue;
		build(v, x);
		num[x] += num[v];
		sum[x] += sum[v];
	}
	return ;
}
 
void DFS(int x, int f){
	for(int i=head[x]; ~i; i=edge[i].next){
		int v = edge[i].v;
		if(v == f)continue;
		if(sum[v] >= aim * num[v]) {
			DFS(v, x);
			if(h[v] > aim){
				ans.push_back((ansNode){v, x, h[v] - aim});
				h[x] += h[v] - aim;
				sum[v] -= h[v] - aim;
				h[v] = aim;
			}
		}
	}
 
	for(int i=head[x]; ~i; i=edge[i].next){
		int v = edge[i].v;
		if(v == f)continue;
		if(sum[v] < aim * num[v]) {
			ans.push_back((ansNode){ x, v, aim*num[v] - sum[v] });
			h[x] -= aim*num[v] - sum[v];
			h[v] += aim*num[v] - sum[v];
			sum[v] = aim*num[v];
			DFS(v, x);
		}
	}
 
	return ;
}
 
int main()
{
	memset(head, -1, sizeof(head));
	int x, y;
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &h[i]);
		aim += h[i];
	}
	for (int i = 1; i <= n-1; ++i) {
		scanf("%d %d", &x, &y);
		add_edge(x, y);
		add_edge(y, x);
	}
	build(1, 0);
	aim /= n;
	DFS(1, 0);
 
	printf("%d\n",(int)ans.size());
	for(auto i : ans){
		printf("%d %d %lld\n", i.x, i.y, i.v);
	}
	return 0;
}
/app/www/public/data/pages/icpc/problems/usaco22dec_barn_tree_s.txt · 最后更改: 2023/04/11 06:31 由 温婕莺