[USACO10MAR]Great Cow Gathering G 题解报告

题目描述

Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。

每个奶牛居住在 N 个农场中的一个,这些农场由 N−1 条道路连接,并且从任意一个农场都能够到达另外一个农场。道路 ii 连接农场\(Ai\)\(Bi\),长度为 \(Li\)。集会可以在 \(N\) 个农场中的任意一个举行。另外,每个牛棚中居住着 Ci 只奶牛。

在选择集会的地点的时候,Bessie 希望最大化方便的程度(也就是最小化不方便程度)。比如选择第 X 个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和(比如,农场 i 到达农场 X 的距离是 20,那么总路程就是 Ci×20)。帮助 Bessie 找出最方便的地点来举行大集会。

输入输出格式

输入格式

第一行一个整数 N 。 第二到 N+1 行:第 i+1 行有一个整数 Ci。 第 N+2 行到 2*N 行:第 i+N+1 行为 3 个整数:\(Ai\),\(Bi\)\(Li\)

输出格式

一行一个整数,表示最小的不方便值。

输入输出样例

输入样例 #1

5 
1 
1 
0 
0 
2 
1 3 1 
2 3 2 
3 4 3 
4 5 3

输出样例 #1

15

说明

1≤N≤105,1≤Ai≤Bi≤N,0≤Ci,Li≤1000。

思路

读题下来

相当于就是求在一棵无根树中找一个根节点,使得所有点的深度之和最小

即换根DP

注意,跟[POI2008] STA-Station不同的是,在算深度的时候,要乘上当前节点的奶牛数。

递推公式:跟[POI2008] STA-Station一样,不过这里dx的定义有一点点不同

我们可以在第一个dfs中算出在以u为根节点的子树的深度之和,即子树中所有子节点到u的深度之和

还是用两个dfs

第一次,以1为根节点计算一次

第二次计算偏移后的值

最后计算最小值

求出答案

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200100;
ll d[N],c[N],tot[N],f[N],h[N];
ll sum,ans=0x3f,cnt=0,n;
struct Node {
	ll v,nxt,w;
} tr[N];
void dfsa(ll u,ll fa) {
	ll cnt=0;
	for(ll i=h[u]; i; i=tr[i].nxt) {
		ll v=tr[i].v;
		if(v!=fa) {
			ll s=dfsa(v,u);
			d[u]+=d[v]+tr[i].w*s;
			cnt+=s;
		}
	}
	tot[u]=cnt+c[u];
}
void dfsb(ll u,ll fa) {
	for(ll i=h[u]; i; i=tr[i].nxt) {
		ll v=tr[i].v;
		if(v!=fa) {
			ll w=tr[i].w;
			f[v]=f[u]-tot[v]*w+(sum-tot[v])*w;
			dfsb(v,u);
		}
	}
}
void add(int u,int v){
	tr[++cnt].to=v;
	tr[cnt].nxt=hd[u];
	hd[u]=cnt;
}
int main() {
	scanf("%d",&n);
	for(ll i=1; i<=n; ++i) {
		scanf("%d",&c[i]);
		sum+=c[i];
	}
	for(ll i=1; i<n; ++i) {
		scafn("%lld%lld%lld",&u,&v,&w);
		ans(u,v,w);
		ans(v,u,w);
	}
	dfsa(1,1);
	dfsb(1,1);
	for(ll i=1; i<=n; ++i){
		ans=min(ans,f[i]);
	}
	printf("%ll,ans+d[1]);
	return 0;
}

完结撒花❀
**

posted @ 2022-06-06 17:17  _Youngxy  阅读(65)  评论(0)    收藏  举报