[题解]AT_abc270_f [ABC270F] Transportation

思路

首先,可以将所有岛屿的连通关系可以分为四种情况:

  1. 只用桥。
  2. 只用桥和机场。
  3. 只用桥和港口。
  4. 桥、机场、港口都用。

那么,只用桥的情况十分好处理,直接跑一边 Kruskal 即可。

但是对于机场和港口都是点权,不能直接跑 Kruskal,所以考虑转化为边权。

不难想到直接用一个超级原点,连接这些点,然后跑 Kruskal 即可。

那么,为什么不能直接揉成一张图跑跑 Kruskal 呢?因为如果揉成一张图,那么跑 Kruskal,相当于说只能处理到第 4 种情况。(因为两个超级原点都会被保留)

Code

#include <bits/stdc++.h>  
#define int long long  
#define re register  
  
using namespace std;  
  
const int N = 2e5 + 10,M = 6e5 + 10,inf = 1e18 + 10;  
int n,m,idx,pidx,ans = inf;  
int f[N],arr[N],brr[N];  
  
struct node{  
    int a;  
    int b;  
    int w;  
  
    bool operator <(const node &t)const{  
        return w < t.w;  
    }  
}pg[M],g[M];  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 1) + (r << 3) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
inline int find(int x){  
    if (f[x] != x) return f[x] = find(f[x]);  
    return f[x];  
}  
  
inline void merge(int x,int y){  
    int a = find(x);  
    int b = find(y);  
    f[a] = b;  
}  
  
inline void kruskal(int num){  
    int res = 0,cnt = 1;  
    for (re int i = 1;i <= num;i++) f[i] = i;  
    sort(g + 1,g + idx + 1);  
    for (re int i = 1;i <= idx;i++){  
        int a = g[i].a;  
        int b = g[i].b;  
        int w = g[i].w;  
        if (find(a) == find(b)) continue;  
        cnt++;  
        res += w;  
        merge(a,b);  
    }  
    if (cnt == num) ans = min(ans,res);  
}  
  
signed main(){  
    n = read();  
    m = read();  
    for (re int i = 1;i <= n;i++) arr[i] = read();  
    for (re int i = 1;i <= n;i++) brr[i] = read();  
    for (re int i = 1;i <= m;i++){  
        int a,b,c;  
        a = read();  
        b = read();  
        c = read();  
        g[++idx] = pg[++pidx] = {a,b,c};  
    }  
    kruskal(n);  
    idx = pidx;  
    memcpy(g,pg,sizeof(pg));  
    for (re int i = 1;i <= n;i++) g[++idx] = {i,n + 1,arr[i]};  
    kruskal(n + 1);  
    idx = pidx;  
    memcpy(g,pg,sizeof(pg));  
    for (re int i = 1;i <= n;i++) g[++idx] = {i,n + 1,brr[i]};  
    kruskal(n + 1);  
    for (re int i = 1;i <= n;i++) g[++idx] = {i,n + 2,arr[i]};  
    kruskal(n + 2);  
    printf("%lld",ans);  
    return 0;  
}  

作者:WaterSun

出处:https://www.cnblogs.com/WaterSun/p/18262370

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   WBIKPS  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示