传送门(洛谷)
f [ i ] 表 示 i 到 各 个 节 点 的 距 离 和 , d i s [ i ] 表 示 在 i 号 节 点 举 办 会 议 的 代 价 最 小 值 f[i]表示i到各个节点的距离和,dis[i]表示在i号节点举办会议的代价最小值 f[i]表示i到各个节点的距离和,dis[i]表示在i号节点举办会议的代价最小值
f [ u ] + = f [ v ] + s i z e [ v ] ∗ e [ i ] . w f[u]+=f[v]+size[v]*e[i].w f[u]+=f[v]+size[v]∗e[i].w
d i s [ v ] = d i s [ u ] − s i z e [ v ] ∗ e [ i ] . w + ( t o t − s i z e [ v ] ) ∗ e [ i ] . w dis[v]=dis[u]-size[v]*e[i].w+(tot-size[v])*e[i].w dis[v]=dis[u]−size[v]∗e[i].w+(tot−size[v])∗e[i].w 向儿子偏移,则点的距离会发生变化
初始化: d i s [ 1 ] = f [ 1 ] dis[1]=f[1] dis[1]=f[1] 在根节点举办一定是整棵树的距离
Code
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
#define don(i,a,b) for(register int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int maxn=1e6+10;
const int maxm=1e3+10;
ll n,cnt,ans=LONG_MAX,tot;
ll num[maxn],head[maxn],dis[maxn],f[maxn],size[maxn];
template <class t> inline void read(t &x) {
int f=1;x=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
struct node{
int v,w,nex;
}e[maxn];
void add(int u,int v,int w) {
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
void readdata() {
read(n);
rep(i,1,n) {read(num[i]);tot+=num[i];}
rep(i,1,n-1) {
int u,v,w;
read(u),read(v),read(w);
add(u,v,w);
add(v,u,w);
}
}
void dfs1(int u,int fa) {
size[u]=num[u];
for(int i=head[u];i;i=e[i].nex) {
int v=e[i].v;
if(v==fa) continue;
dfs1(v,u);
size[u]+=size[v];
f[u]+=f[v]+size[v]*e[i].w;
}
}
void dfs2(int u,int fa) {
for(int i=head[u];i;i=e[i].nex) {
int v=e[i].v;
if(v==fa) continue;
dis[v]=1LL*dis[u]-size[v]*e[i].w+(tot-size[v])*e[i].w;
ans=min(ans,dis[v]);
dfs2(v,u);
}
}
void work() {
memset(f,false,sizeof(f));
memset(dis,false,sizeof(dis));
memset(size,false,sizeof(size));
dfs1(1,0);
dis[1]=f[1];
ans=min(ans,dis[1]);
dfs2(1,0);//dfs1进行离线处理,先算出距离再dp
printf("%lld\n",ans);
}
int main()
{
//freopen("input.txt","r",stdin);
readdata();
work();
return 0;
}