題目描述
Bessie正在計劃一年一度的奶牛大集會,來自全國各地的奶牛將來參加這一次集會。當然,她會選擇最方便的地點來舉辦這次集會。每個奶牛居住在 N(1<=N<=100,000) 個農場中的一個,這些農場由N-1條道路連線,並且從任意一個農場都能夠到達另外一個農場。道路i連線農場A_i和B_i(1 <= A_i <=N; 1 <= B_i <= N),長度為L_i(1 <= L_i <= 1,000)。集會可以在N個農場中的任意一個舉行。另外,每個牛棚中居住者C_i(0 <= C_i <= 1,000)只奶牛。在選擇集會的地點的時候,Bessie希望最大化方便的程度(也就是最小化不方便程度)。比如選擇第X個農場作為集會地點,它的不方便程度是其它牛棚中每隻奶牛去參加集會所走的路程之和,(比如,農場i到達農場X的距離是20,那麼總路程就是C_i*20)。幫助Bessie找出最方便的地點來舉行大集會。 考慮一個由五個農場組成的國家,分別由長度各異的道路連線起來。在所有農場中,3號和4號沒有奶牛居住。

輸入
第一行:一個整數N * 第二到N+1行:第i+1行有一個整數C_i * 第N+2行到2*N行,第i+N+1行為3個整數:A_i,B_i和L_i。
輸出
* 第一行:一個值,表示最小的不方便值。
樣例輸入
5
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
樣例輸出
15
這是一道入門的樹上問題。首先說一下暴力,以每一個點為根對整棵樹做一遍dfs,最後找出最優解,時間複雜度是O(n^2)。但顯然並不用這麼麻煩,對於以i為集會點的結果,如果把集會點移向與i相連的點j,那麼,把這條連線i與j的邊斷開後可以把整個樹變成兩個聯通塊。把集會點從i移向j後,i所在聯通塊所有點費用要加上這條邊邊權費用,j所在聯通塊所有點費用要減掉這條邊邊權的費用。那麼只要處理出一個點的結果,再O(n)轉移就可以了。以一個點為根,dfs向子節點轉移,對於一個節點i轉移到它的一個子節點j,兩個聯通塊節點數分別是以j為根的子樹節點數和總節點數-以j為根的子樹節點數。
最後附上程式碼。
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long size[100010];
int head[100010];
int next[200010];
int to[200010];
long long val[200010];
int f[100010];
long long s[100010];
long long a[100010];
int x,y;
long long v;
int n;
int tot;
long long sum;
long long ans;
void add(int x,int y,long long v)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=v;
}
void dfs(int x,int fa)
{
f[x]=fa;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs(to[i],x);
size[x]+=size[to[i]];
}
}
}
void dfs2(int x,long long dep)
{
ans+=dep*a[x];
for(int i=head[x];i;i=next[i])
{
if(to[i]!=f[x])
{
dfs2(to[i],dep+val[i]);
}
}
}
void find(int x)
{
for(int i=head[x];i;i=next[i])
{
if(to[i]!=f[x])
{
s[to[i]]=s[x]-size[to[i]]*val[i]+(sum-size[to[i]])*val[i];
find(to[i]);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&size[i]);
a[i]=size[i];
sum+=size[i];
}
for(int i=1;i<n;i++)
{
scanf("%d%d%lld",&x,&y,&v);
add(x,y,v);
add(y,x,v);
}
dfs(1,1);
dfs2(1,0ll);
s[1]=ans;
find(1);
ans=1ll<<62;
for(int i=1;i<=n;i++)
{
ans=min(ans,s[i]);
}
printf("%lld",ans);
}