题目:
题解:
又是一道毒牛题
可以先求出以1为集合地点的权值,主要是维护每个节点所具有的牛的数量、每个节点到1的距离
然后就可以利用差值维护这棵树,达到O(1)转换集合场所(让要去节点的牛后退一步,其他所有的牛前进一步
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 100005
#define LL long long
using namespace std;
int r[N],tot,nxt[N*2],point[N],v[N*2],c[N*2];
LL cost,ans,size[N],len[N];
void addline(int x,int y,int z)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;
}
void dfs(int x,int fa)
{
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
len[v[i]]=len[x]+c[i];
cost+=len[v[i]]*r[v[i]];
dfs(v[i],x);
size[x]+=size[v[i]];
}
}
void answer(int x,int fa,LL cost)
{
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
LL t=cost-size[v[i]]*c[i]+(size[1]-size[v[i]])*c[i];
ans=min(ans,t);
answer(v[i],x,t);
}
}
int main()
{
int n,i;
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d",&r[i]),size[i]=r[i];
for (i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addline(x,y,z);
}
dfs(1,0);ans=cost;
answer(1,0,cost);
printf("%lld",ans);
}