[USACO10MAR]伟大的奶牛聚集
首先要想到\(dp\)转移方程,设\(g[v]\)为设\(v\)为牛棚的花费,可以由其父亲转移而来
\[g[v]=g[u]-sz[v]*w+(tot-sz[v])*w\]
之后我们随便制定一个树根算出初态(比如设定\(1\)为树根初态)即可开始转移
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 100010
#define ll long long
ll f[MAXN];
ll g[MAXN];
int head[MAXN],nxt[MAXN*2],vv[MAXN*2],ww[MAXN*2],tot;
inline void add_edge(int u, int v, int w){
vv[++tot]=v;
ww[tot]=w;
nxt[tot]=head[u];
head[u]=tot;
}
int sz[MAXN];
int c[MAXN];
void dfs(int u, int fa){
sz[u]=c[u];
for(int i=head[u];i;i=nxt[i]){
int v=vv[i],w=ww[i];
if(v==fa) continue;
dfs(v, u);
sz[u]+=sz[v];
f[u]+=f[v]+(ll)sz[v]*w;
}
}
const ll INF=1e18;
ll ans=INF;
void dfs2(int u, int fa){
for(int i=head[u];i;i=nxt[i]){
int v=vv[i],w=ww[i];
if(v==fa) continue;
g[v]=g[u]+(ll)w*(sz[1]-sz[v])-(ll)sz[v]*w;
ans=min(ans, g[v]);
dfs2(v, u);
}
}
int n;
int main(){
scanf("%d", &n);
for(int i=1;i<=n;++i) scanf("%d", &c[i]);
for(int i=1;i<n;++i){
int u,v,w;scanf("%d %d %d", &u, &v, &w);
add_edge(u, v, w);
add_edge(v, u, w);
}
dfs(1,1);
g[1]=f[1];
ans=min(ans, g[1]);
dfs2(1, 1);
printf("%lld\n", ans);
return 0;
}
/*
f[u]+=f[v]+sz[v]*w
g[v]=g[u]+w*(cnt-sz[v])-sz[v]*w
*/