题意:n个地点构成一棵树,第 i 个地点有 t_i 个人,现要选一个地点开会,求所有人行走距离之和的最小值。N<=10^5
分析:先任选一个地点,求出总代价,然后就能求出相邻点的代价,一遍dfs就能求出所有点的代价。
dfs会爆栈,需要开内存挂:#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 100001 #pragma comment(linker, "/STACK:1024000000,1024000000") typedef __int64 LL; int n,t[N],e,sum; int first[N],next[N<<1],v[N<<1],w[N<<1]; LL dp[N],tsum[N],ans[N]; void init() { e=sum=0; memset(first,-1,sizeof(first)); } void add(int a,int b,int c) { v[e]=b; w[e]=c; next[e]=first[a]; first[a]=e++; } void DP(int a,int fa) { dp[a]=0; tsum[a]=t[a]; int i,b; for(i=first[a];~i;i=next[i]) { b=v[i]; if(b==fa) continue; DP(b,a); tsum[a]+=tsum[b]; dp[a]+=dp[b]+tsum[b]*w[i]; } } void dfs(int a,int fa,LL cost) { int i,b; for(i=first[a];~i;i=next[i]) { b=v[i]; if(b^fa) dfs(b,a,ans[b]=cost+(sum-2*tsum[b])*w[i]); } } int main() { int a,b,c; while(~scanf("%d",&n)) { init(); for(int i=1;i<=n;i++) { scanf("%d",&t[i]); sum+=t[i]; } for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } DP(1,0); dfs(1,0,ans[1]=dp[1]); LL ANS=ans[1]; for(int i=2;i<=n;i++) ANS=min(ANS,ans[i]); printf("%I64d\n",ANS); } return 0; }