AT2643 [ARC076B] Built?

原题链接

  • 题意:给出 \(n <= 1e5\) 个网格图点位置,然后让求所有点连起来的最小花费,即特殊的最小生成树,两个点之间相连的花费是 \(min(|x_a - x_b|, |y_a - y_b|)\)
  • 题解:好像和之前做过一道dij的cf题类似。首先 \(n^2\) 建边不可取,那就是先按横坐标排序,然后相邻之间 \(|x_i - x_j|\)必然是最优的,加入预选,然后再按照 \(y\) 坐标,然后也是相邻的 \(|y_i - y_j|\) 是最优的,然后最后就是 \(kruskal\)
  • 代码:
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f;
const ll N = 1e5 + 9;
struct edge {
    int x, y, w;
}e[N << 2], a[N << 2];
struct node {
    int x, y, id;
}p[N];
bool cmp1(node a, node b) {return a.x < b.x;}
bool cmp2(node a, node b) {return a.y < b.y;}
bool cmp3(edge a, edge b) {return a.w < b.w;}
int f[N << 2];
int Find(int x){return f[x] == x?x:f[x] = Find(f[x]);}
signed main() {
    int n;scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf("%d%d", &p[i].x, &p[i].y);
        p[i].id = i;
    }
    for (int i = 0; i <= n + 2; i ++) f[i] = i;
    sort(p + 1, p + 1 + n, cmp1);
    int nn = 0;
    for (int i = 1; i < n; i ++) e[++nn] = {p[i].id, p[i + 1].id, abs(p[i].x - p[i + 1].x)};
    sort(p + 1, p + 1 + n, cmp2);
    for (int i = 1; i < n; i++) e[++nn] = {p[i].id, p[i + 1].id, abs(p[i].y - p[i + 1].y)};
    sort(e + 1, e + 1 + nn, cmp3);
    int ans =0 ;
    for (int i = 1; i <= nn; i ++) {
        int fx = Find(e[i].x);
        int fy = Find(e[i].y);
        if (fx == fy)continue;
        f[fx] = fy;
        ans += e[i].w;
    }
    printf("%d\n", ans);
}
posted @ 2021-04-22 12:06  u_yan  阅读(50)  评论(0编辑  收藏  举报