 /**//*
题意:一棵树上,每个节点有cnt[i]个人 每条边有权值
现要求一个点,使得其他点到该点的所有代价最小
代价即 ∑人数*经过边的权值

tree dp 自底向上 自顶向下更新2次即可

先dfs1求得:
ans[u] 以u为根的子树,所有点到u的代价
sum[u] u及其子树所有节点的人数
同时记录父边的权值preE[u]

再dfs2来更新得到正确的ans[u](即整棵树以u为目标节点的代价)
即:ans[u]=ans[p]-sum[u]*preE[u]+(tot-sum[u])*preE[u];
这时ans[p]保存的是所有点到p的代价,当然包括从u的及其子树到p的代价,所以要减去
+除u的子树外的所有节点到达u的代价

跟hdu 2196 poj 3585 CII 4614 一样,2次dfs
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

const int MAXN = 100010;

vector<pair<int,int> >G[MAXN];

long long ans[MAXN],sum[MAXN];
long long tot;
int preE[MAXN],cnt[MAXN];

void dfs1(int u,int p)
  {
sum[u]=cnt[u];
ans[u]=0;
for(int i=0,size=G[u].size();i<size;i++)
 {
int v=G[u][i].first,c=G[u][i].second;
if(v==p)continue;
dfs1(v,u);
preE[v]=c;
sum[u]+=sum[v];
ans[u]+=(ans[v]+sum[v]*c);
}
}
void dfs2(int u,int p)
  {
if(u!=1)
 {
ans[u]=ans[p]-sum[u]*preE[u]+(tot-sum[u])*preE[u];
}
for(int i=0,size=G[u].size();i<size;i++)
 {
int v=G[u][i].first;
if(v==p)continue;
dfs2(v,u);
}
}
int main()
  {

int n;
int a,b,c;
while(~scanf("%d",&n))
 {
tot=0;
for(int i=1;i<=n;i++)
 {
G[i].clear();
scanf("%d",&cnt[i]);
tot+=cnt[i];
}
for(int i=1;i<n;i++)
 {
scanf("%d%d%d",&a,&b,&c);
G[a].push_back(make_pair(b,c));
G[b].push_back(make_pair(a,c));
}
preE[1]=0;
dfs1(1,0);
dfs2(1,0);
printf("%lld\n",*min_element(ans+1,ans+1+n));
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|