#换根dp#洛谷 2986 [USACO10MAR]Great Cow Gathering G

题目


分析

处理出所有点到根节点的答案,然后换根依次求最小值


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long lll; const int N=200011;
struct node{int y,w,next;}e[N<<1];
lll dp[N],W[N],ans=1e18,s; int n,k=1,a[N],as[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline lll min(lll a,lll b){return a<b?a:b;}
inline void dfs1(int x,int fa){
	W[x]=a[x];
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fa){
		dfs1(e[i].y,x);
		dp[x]+=dp[e[i].y]+e[i].w*W[e[i].y];
		W[x]+=W[e[i].y];
	}
}
inline void dfs2(int x,int fa){
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fa){
		dp[e[i].y]=dp[x]-W[e[i].y]*e[i].w+(s-W[e[i].y])*e[i].w;
		dfs2(e[i].y,x);
	}
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut(),s+=a[i];
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut(),w=iut();
		e[++k]=(node){y,w,as[x]},as[x]=k;
		e[++k]=(node){x,w,as[y]},as[y]=k;
	}
	dfs1(1,0),dfs2(1,0);
	for (rr int i=1;i<=n;++i) ans=min(ans,dp[i]);
	return !printf("%lld",ans);
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13531595.html