[USACO10MAR]Great Cow Gathering G

题目

题目描述
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;
}
发布了809 篇原创文章 · 获赞 396 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/105529767