CF1095F Make It Connected
一眼kruskal板子题,又看了一眼被数据范围劝退,去原题看了一眼div3的题,仔细思考了一下。
我们把所有边考虑一下,除了特殊边,剩下边都是 \(a_i + a_j\) 的形式。那么显然,在固定一个的情况下,一个最小肯定最优,那么我们容易想到一定存在一个 \(a_{mini}\) 使得 \(a_{i} + a_{mini} \le a_{i} + a_{j}\) 那么我们只需要 \(a_{i}+a_{mini}\) 的 \(N-1\) 条边和 \(M\) 条特殊边就行了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6+10, INF = 0x3f3f3f3f3f3f3f3f;
ll N, M, fa[MAXN], val[MAXN];
struct edge {
ll x, y, v;
edge(ll _x, ll _y, ll _v): x(_x), y(_y), v(_v) {}
edge() {}
friend bool operator < (edge a, edge b) {
return a.v < b.v;
}
} E[MAXN];
ll ans = 0, minn = INF, mini = 0;
ll find_(ll);
void onion(ll, ll);
int main() {
scanf("%lld%lld", &N, &M);
for (ll i = 1; i <= N; i++) {
scanf("%lld", val+i), fa[i] = i;
if (minn > val[i])
minn = val[i], mini = i;
}
for (ll i = 1; i <= M; i++) {
scanf("%lld%lld%lld", &E[i].x, &E[i].y, &E[i].v);
E[i].v = min(E[i].v, val[E[i].x] + val[E[i].y]);
}
for (ll i = 1; i <= N; i++) if (i != mini)
E[++M] = edge(i, mini, val[i] + val[mini]);
sort(E+1, E+M+1);
for (ll i = 1, qq = 1; i < N && qq <= M; i++, qq++) {
ll fx = find_(E[qq].x), fy = find_(E[qq].y);
if (fx == fy) {i--; continue;}
onion(fx, fy);
ans += E[qq].v;
}
printf("%lld\n", ans);
return 0;
}
void onion(ll x, ll y) {
ll fx = find_(x), fy = find_(y);
if (fx != fy) {
fa[fx] = fy;
val[fy] = min(val[fy], val[fx]);
}
}
ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}
希望我们都有一个光明的未来