/**//* 题意:一棵树上,每个节点有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
搜索
最新评论
|
|