问题描述

圣诞节快到了,蒜头君准备做一棵大圣诞树。

这棵树被表示成一组被编号的结点和一些边的集合,树的结点从 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);
}