Make It Connected CodeForces - 1095F (建图+最小生成树)

Make It Connected

CodeForces - 1095F

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+ay coins. 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

3 2
1 3 3
2 3 5
2 1 1

Output

5

Input

4 0
1 3 3 7

Output

16

Input

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

Output

18

Note

In the first example it is possible to connect 11 to 22 using special offer 22, and then 11 to 33 without using any offers.

In next two examples the optimal answer may be achieved without using special offers.

 题意:

赵老师因为感冒回家进行休息
在睡梦中他竟然来到了一个神奇的地方
这个地方可以抽象为n个点,每个点有一个点权,第i个点的点权为a_i
此时,他的脑海里竟然浮现出了一段文字:
卑鄙的异乡人啊,
你太年轻太简单了,有时还很朴素
我需要给你一些微小的考验
所有点联通之时,
返程之路将浮现。

赵老师知道,想要在点i和点j之间连一条边,所需时间为a_i+a_j
但是作为一个单身多年的魔法师,他可以施展m次魔法,第i次魔法可以在x_i和y_i之间连一条边,所需时间是w_i
赵老师清楚的记得,第二天他还需要上课,因此你需要帮他算出将所有点联通所需的最短时间是多少

 思路:

将每一个节点和除了它自己以外的其他n-1个节点中,权值最小的节点相连接。

这样一共是n个边,

还有题目给出的m个边。

在这n+m个边中跑Kruskal算法,求出最小生成树的代价即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}

inline void getInt(int* p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct Edge
{
    int f, t;
    ll  w;
    Edge() {}
    Edge(int ff, int tt, ll ww)
    {
        if(ff==9&&tt==4)
        {
            ff=9;
        }
        f = ff;
        t = tt;
        w = ww;
    }
};
std::vector<Edge> edge;
bool cmp(Edge a, Edge b)
{
    return a.w < b.w;
}
// 并查集部分
int fa[maxn];
int findpar(int x)
{
    if (fa[x] == x)
        return x;
    else
        return fa[x] = findpar(fa[x]);
}
void initufs(int n)
{
    repd(i, 1, n)
    {
        fa[i] = i;
    }
}
void Merge(int x,int y)
{
    x=findpar(x);
    y=findpar(y);
    if(x!=y)
    {
        fa[x]=y;
    }
}
int n, m; //
ll a[maxn];
ll Kruskal()
{
    ll res = 0ll;
    initufs(n);
    int cnt = 0; // 记录了MST加入了几个节点
    for (int i = 0; i < edge.size(); i++)
    {
        int u = findpar(edge[i].f);
        int v = findpar(edge[i].t);
        if (u == v)
            continue;
        Merge(u,v);
        res += edge[i].w;
        cnt++;
        if (cnt == n - 1) // 已经加满了树
            break;
    }
    if (cnt != n - 1)
        return -1;
    else
        return res;
}
typedef pair<ll, int> pli;
pli pre[maxn];
pli last[maxn];
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    du2(n, m);
    repd(i, 1, n)
    {
        scanf("%lld", &a[i]);
    }
    pre[1] = mp(a[1], 1);
    last[n] = mp(a[n], n);
    repd(i, 2, n)
    {
        if (a[i] < pre[i - 1].fi)
        {
            pre[i] = mp(a[i], i);
        } else
        {
            pre[i] = pre[i - 1];
        }
    }
    for (int i = n - 1; i >= 1; --i)
    {
        if (a[i] < last[i + 1].fi)
        {
            last[i] = mp(a[i], i);
        } else
        {
            last[i] = last[i + 1];
        }
    }
    edge.push_back(Edge(1, last[2].se, last[2].fi + a[1]));
    edge.push_back(Edge(n, pre[n - 1].se, pre[n - 1].fi + a[n]));
    repd(i, 2, n - 1)
    {
        if (last[i + 1].fi < pre[i - 1].fi)
        {
            edge.push_back(Edge(i, last[i + 1].se, last[i + 1].fi + a[i]));
        } else
        {
            edge.push_back(Edge(i, pre[i - 1].se, pre[i - 1].fi + a[i]));
        }
    }
    repd(i, 1, m)
    {
        int x, y;
        ll z;
        scanf("%d %d %lld", &x, &y, &z);
        edge.push_back(Edge(x, y, z));
    }
    sort(ALL(edge), cmp);
    if (n == 1)
    {
        puts("0");
        return 0;
    }
    printf("%lld\n", Kruskal());
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}


转载于:https://www.cnblogs.com/qieqiemin/p/11626064.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值