题目
题目描述
Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。
每个奶牛居住在 NN 个农场中的一个,这些农场由 N-1N−1 条道路连接,并且从任意一个农场都能够到达另外一个农场。道路 ii 连接农场 A_iA
i
和 B_iB
i
,长度为 L_iL
i
。集会可以在 NN 个农场中的任意一个举行。另外,每个牛棚中居住着 C_iC
i
只奶牛。
在选择集会的地点的时候,Bessie 希望最大化方便的程度(也就是最小化不方便程度)。比如选择第 XX 个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和(比如,农场 ii 到达农场 XX 的距离是 2020,那么总路程就是 C_i\times 20C
i
×20)。帮助 Bessie 找出最方便的地点来举行大集会。
输入格式
第一行一个整数 NN 。
第二到 N+1N+1 行:第 i+1i+1 行有一个整数 C_iC
i
。
第 N+2N+2 行到 2N2N 行:第 i+N+1i+N+1 行为 33 个整数:A_i,B_iA
i
,B
i
和 L_iL
i
。
输出格式
一行一个整数,表示最小的不方便值。
输入输出样例
输入 #1 复制
5
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
输出 #1 复制
15
说明/提示
1\leq N\leq 10^51≤N≤10
5
,1\leq A_i\leq B_i\leq N1≤A
i
≤B
i
≤N,0 \leq C_i,L_i \leq 10^30≤C
i
,L
i
≤10
3
。
思路
一类经典的树形dp问题。
考虑 f[i] 表达以i为根子树中奶牛到i的距离和。
第一次dfs从下至上递推出各点的 f[i] 和子树奶牛数 siz[i]
画图易知每个点的答案 d[i] 满足的方程
d[v] = d[u] - siz[v]*a[i].w + (cnt - siz[v])*a[i].w;
通过第二次dfs推得各点的 d[i]
显然最小的 d[i] 即为答案
代码
#include<bits.stdc++.h>
#define ll long long
using namespace std;
const int N = 1000005;
const ll INF = 1e55;
inline int read() {
int s = 1, w= 0; char c = getchar();
for(; !isdigit(c); c=getchar()) if(c=='-') s = -1;
for(; isdigit(c); c=getchar()) w = 10*w+c-'0';
return s*w;
}
ll m,n,ans=INF,cnt,inde,head[N],siz[N],c[N],f[N],d[N];
struct Edge{
ll nxt,to,w;
}a[N];
inline void add(int x,int y,int w){
a[++inde].to=y;
a[inde].nxt=head[x];
a[inde].w=w;
head[x]=inde;
}
inline void dfs (int u, int fa) {
siz[u] = c[u];
for(int i = head[u]; i; i = a[i].nxt) {
int v = a[i].to;
if(v == fa) continue;
dfs(v,u);
siz[u] += siz[v];
f[u] = f[u] + f[v] + siz[v] * a[i].w;
}
}
inline void dp (int u, int fa) {
for(int i = head[u]; i; i = a[i].nxt) {
int v = a[i].to;
if(v == fa) continue;
d[v] = 1LL*d[u] - siz[v]*a[i].w + (cnt - siz[v])*a[i].w;
ans = min(ans, d[v]);
dp(v,u);
}
}
int main() {
int u,v,w;
n = read();
for(int i=1; i<=n; i++){
c[i]=read();
cnt += c[i];
}
for(int j=1; j<n; j++){
u = read(); v = read(); w=read();
add(u,v,w);
add(v,u,w);
}
dfs(1,0);
d[1]=f[1];
ans = min(ans, d[1]);
dp(1,0);
printf("%lld\n", ans*1LL);
return 0;
}