圣诞树

问题描述

圣诞节快到了,蒜头君准备做一棵大圣诞树。
这棵树被表示成一组被编号的结点和一些边的集合,树的结点从 1 到 n 编号,树的根永远是 1。每个结点都有一个自身特有的数值,称为它的权重,各个结点的权重可能不同。对于一棵做完的树来说,每条边都有一个价值 ve,若设这条边 e 连接结点 i 和结点 j,且 i 为 j的父结点(根是最老的祖先),则该边的价值ve=sj*we,sj表示结点 j 的所有子孙及它自己的权重之和,we表示边 e 的权值。
现在蒜头君想造一棵树,他有 m 条边可以选择,使得树上所有边的总价值最小,并且所有的点都在树上,因为蒜头君喜欢大树。

输入格式

第一行输入两个整数 n 和 m(0≤n,m≤50,000),表示结点总数和可供选择的边数。
接下来输入一行,输入 n 个整数,依次表示每个结点的权重。
接下来输入 m 行,每行输入 3 个正整数a,b,c(1≤a,b,≤n,1≤c≤10,000),表示结点 a 和结点 b 之间有一条权值为 c 的边可供造树选择。

输出格式

输出一行,如果构造不出这样的树,请输出No Answer,否则输出一个整数,表示造树的最小价值。

样例输入

4 4
10 20 30 40
1 2 3
2 3 2
1 3 5
2 4 1

样例输出

370

思路

装模做样,不堪一击

随便画个图

Ans = (20+30+40) * 3 = 40 * 1+30*2

笑死 = 20 * 3+30 * 5+40 * 4 = 370

很显然, n 节点与1联通的cost为 d[n] (最短路) * S[n] (节点权值)

当然证明也是很简单的

设节点n , 很显然n的权值会被贡献给它的所有祖先权值 , 所以 C = S[n] * (d[n]) (即其所有祖先与1联通权值和即最短路 ( 结合律不多说
// 如此拉跨的题解,就连我都不心潮澎湃 (

代码

#include <bits/stdc++.h>
using namespace std;
// C(J) = D[J] * w[j] * S[j] (fixed);
const int maxn = 5e4 + 10;
int n, m;
int S[maxn];
struct edge {
    int v, w;
};
set< pair< long long, int > > min_heap;
vector< edge > G[maxn];
long long d[maxn];
void dij() {
    min_heap.insert({0, 1});
    d[1] = 0;
    while (min_heap.size()) {
        int u = min_heap.begin()->second;
        min_heap.erase(min_heap.begin());
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i].v, w = G[u][i].w;
            if (w + d[u] < d[v]) {
                min_heap.erase({d[v], v});
                d[v] = w + d[u];
                min_heap.insert({d[v], v});
            }
        }
    }
}
const long long inf = 0x3f3f3f3f3f3f3f3f;
int main() {
    freopen("chris.in", "r", stdin);
    freopen("chris.out", "w", stdout);
    memset(d, 0x3f, sizeof(d));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &S[i]);
    }
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        G[u].push_back({v, w});
        G[v].push_back({u, w});
    }
    dij();
    long long ans = 0;
    for (int i = 1; i <= n; ++i) {
        if (d[i] == inf) {
            printf("No Answer");
            return 0;
        }
        ans += d[i] * S[i];
    }
    printf("%lld", ans);
}
posted @ 2021-07-28 22:34  周昂没有周昂  阅读(154)  评论(0)    收藏  举报