codeforces 1095F Make It Connected 最小生成树

F. Make It Connected

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given an undirected graph consisting of nn vertices. A number is written on each vertex; the number on vertex ii is aiai. Initially there are no edges in the graph.

You may add some edges to this graph, but you have to pay for them. The cost of adding an edge between vertices xx and yy is ax+ayax+aycoins. There are also mm special offers, each of them is denoted by three numbers xx, yy and ww, and means that you can add an edge connecting vertices xx and yy and pay ww coins for it. You don't have to use special offers: if there is a pair of vertices xx and yy that has a special offer associated with it, you still may connect these two vertices paying ax+ayax+ay coins for it.

What is the minimum number of coins you have to spend to make the graph connected? Recall that a graph is connected if it's possible to get from any vertex to any other vertex using only the edges belonging to this graph.

Input

The first line contains two integers nn and mm (1≤n≤2⋅1051≤n≤2⋅105, 0≤m≤2⋅1050≤m≤2⋅105) — the number of vertices in the graph and the number of special offers, respectively.

The second line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤10121≤ai≤1012) — the numbers written on the vertices.

Then mm lines follow, each containing three integers xx, yy and ww (1≤x,y≤n1≤x,y≤n, 1≤w≤10121≤w≤1012, x≠yx≠y) denoting a special offer: you may add an edge connecting vertex xx and vertex yy, and this edge will cost ww coins.

Output

Print one integer — the minimum number of coins you have to pay to make the graph connected.

Examples

input

Copy

3 2
1 3 3
2 3 5
2 1 1

output

Copy

5

input

Copy

4 0
1 3 3 7

output

Copy

16

input

Copy

5 4
1 2 3 4 5
1 2 8
1 3 10
1 4 7
1 5 15

output

Copy

18

题目大意:最开始有n个点,第i个点有权值a[ i ],在两个点之间连接一条边的代价为这两个点的权值和,现在额外有m条特殊的边形为(u,v,w)表示连接u和v需要代价w,特殊边可以选择不用,现在问将n个点联通的最小代价。

假设没有那些特殊的边,按照prim来执行生成树的过程,首先选择一个点,然后下一次会将最小权值的点选择进来,从此之后进来的点都是和这个最小权值的点连边进来,所以最小生成树其实就是最小权值点和其他所有点连边,其他的边都是没用的,此时来了m条特殊的边,直接在有用的边加上m条特殊边这个集合上跑最小生成树就好了。

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 2e5 + 10;
#define ll long long
struct node {
    int u, v;
    ll w;
};
int n, m, p[N];
ll a[N];
vector<node> edge;
int find(int x) {
    if (p[x] == x) return x;
    return p[x] = find(p[x]);
}

void merge(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if (fx != fy) p[fx] = fy;
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) p[i] = i;
    int id = 0;
    ll mini = 1e18;
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        if (a[i] < mini) {
            mini = a[i];
            id = i;
        }
    }
    int x, y;
    ll z;
    for (int i = 1; i <= m; i++) {
        scanf("%d%d%lld", &x, &y, &z);
        edge.push_back({x, y, z});
    }
    for (int i = 1; i <= n; i++) if (i != id) edge.push_back({id, i, a[id] + a[i]});
    sort(edge.begin(), edge.end(), [](const node& a, const node& b) {
               return a.w < b.w; 
            });
    ll ans = 0;
    for (int i = 0; i < edge.size(); i++) {
        x = edge[i].u, y = edge[i].v, z = edge[i].w;
        if (find(x) != find(y)) {
            merge(x, y);
            ans += z;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值