题解:分两遍dfs来做,首先求出f[x]表示以x为根且为重心,子树到其加权距离和。
转移即f[x]=\sigma {f[y]+sz[y]*dist(x,y)},其中y是x的子节点,sz为子树大小。
然后利用f数组计算答案,发现答案比f数组多了从父亲来的部分,用v表示
则v[x]=v[y]+(full_size-sz[x])*dist(x,y),其中y为x的父节点,full_size为整棵树的大小(也就是n)。
最后v[x]+f[x]就是以x为重心的代价。取最小值即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<climits>
#define INF LLONG_MAX
#define lint long long
#define MAXN 100010
using namespace std;
struct node{
int to,wgt;
node(int _t,int _w)
{
this->to=_t;
this->wgt=_w;
}
};
vector<node> g[MAXN];lint a[MAXN];
lint minans,f[MAXN],sz[MAXN],fsz;
//lint val[MAXN];
int getf(int x,int fa)
{
for(int i=g[x].size()-1;i>=0;i--)
if(g[x][i].to!=fa)
{
getf(g[x][i].to,x);
sz[x]+=sz[g[x][i].to];
f[x]+=sz[g[x][i].to]*g[x][i].wgt+f[g[x][i].to];
}
return 0;
}
int getans(int x,int fa,lint v)
{
// val[x]=v;
minans=min(minans,f[x]+v);
for(int i=g[x].size()-1;i>=0;i--)
if(g[x][i].to!=fa)
getans(g[x][i].to,x,v+f[x]-sz[g[x][i].to]*g[x][i].wgt-f[g[x][i].to]+(fsz-sz[g[x][i].to])*g[x][i].wgt);
return 0;
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&sz[i]);
for(int i=1;i<=n;i++) a[i]=sz[i];
for(int i=1;i<n;i++)
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);
g[u].push_back(node(v,w));
g[v].push_back(node(u,w));
}
minans=INF;getf(1,0);
// for(int i=1;i<=n;i++)
// printf("%lld ",f[i]);
// printf("\n");
fsz=sz[1];getans(1,0,0LL);
// for(int i=1;i<=n;i++)
// printf("%lld ",val[i]);
// printf("\n");
printf("%lld\n",minans);return 0;
}