 /**//*
題意:一棵樹上,每個節點有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
搜索
最新評論

|
|