CF1095F Make It Connected

Problem

给你 n 个点,每个点有一个权值 ci,已知连接 i,j 两点的代价为 ci+cj,现在还有其他的 m 种连接方法,连接 x,y 的费用为 w

求出让这个图连通的最小代价。

1n2×1050m2×1051ci1012

1x,yn1w1012

Input

第一行两个整数 n,m
第二行 n 个整数,第 i 个整数表示 ci
接下来 m 行,每行三个整数 x,y,w,表示一种连接方法。

Output

一行一个整数表示最小代价。

Sample

Input 1

3 2
1 3 3
2 3 5
2 1 1

Output 1

5

Input 2

4 0
1 3 3 7

Output 2

16

Input 3

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

Output 3

18

Solution

首先总边数是 n×(n1)2+m 的,数量级太大,无法实现。

我们发现完全图中共有 n×(n1)2 条边,但实际上可能对答案产生贡献的是权值最小的前 n1 条边。

那如何找到这 n1 条边呢?

考虑将权值排序,则有 c1c2cn,不难发现将一号节点与剩下 n1 个节点连出的边即为权值最小的前 n1 条边,证明如下。

x,y(x1,y1),一定有 max(c1+cx,c1+cy)cx+cy,所以选完 (1,x)(1,y) 两条边后 x,y 处于同一连通块,两者间不会再连边。

最后将这些边与特殊边共 n+m1 条边跑最小生成树算法即可。

代码:

#include <bits/stdc++.h>

using namespace std;

const int kmax = 2e5 + 5;

struct E {
  long long x, y, w;
} a[kmax * 2];

long long f[kmax], ans, v[kmax];
int n, m, c, g = 1;

int F(int x) {
  return x == f[x] ? x : f[x] = F(f[x]);
}

void U(int x, int y) {
  int fx = F(x), fy = F(y);
  if (fx != fy)
    f[fx] = fy;
  return;
}

int main() {
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> v[i];
    f[i] = i;
    g = (v[g] > v[i] ? i : g); // 找权值最小值
  }
  for (int i = 1; i <= m; i++) {
    cin >> a[i].x >> a[i].y >> a[i].w;
  }
  for (int i = 1; i <= n; i++) {
    if (g != i) { // 不能与自己连
      a[i + m].x = g;
      a[i + m].y = i;
      a[i + m].w = v[i] + v[g]; // 建边
    }
  }
  sort(a + 1, a + m + n + 1, [](E p, E q) { return p.w < q.w; });
  for (int i = 1; i <= m + n; i++) {
    int fx = F(a[i].x);
    int fy = F(a[i].y);
    if (fx != fy) {
      c++, ans += a[i].w; // 累加答案
      U(fx, fy); // 合并
    }
  }
  cout << ans;
  return 0;
}
posted @   ereoth  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示