cplib-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: Manhattan MST (二次元平面上の頂点たちのマンハッタン距離による最小全域木構成)
(graph/manhattan_mst.hpp)

$N$ 個の頂点の $x$, $y$ 座標を与えると,候補となる $O(N)$ 本の辺を(重み,端点 1,端点 2)の形式で列挙する.時間計算量 $O(N \log N)$.

使用方法

vector<int> xs(N), ys(N);
for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];

UnionFind uf(N);
long long mst_weight = 0;
vector<pair<int, int>> mst_edges;
for (auto [w, i, j] : manhattan_mst(xs, ys)) {
    if (uf.unite(i, j)) {
        mst_weight += w;
        mst_edges.emplace_back(i, j);
    }
}

問題例

Verified with

Code

#pragma once
#include <algorithm>
#include <map>
#include <numeric>
#include <tuple>
#include <vector>

// CUT begin
// Manhattan MST: 二次元平面上の頂点たちのマンハッタン距離による minimum spanning tree の O(N) 本の候補辺を列挙
// Complexity: O(N log N)
// output: [(weight_uv, u, v), ...]
// Verified: https://judge.yosupo.jp/problem/manhattanmst, https://www.codechef.com/problems/HKRMAN
// Reference:
// [1] H. Zhou, N. Shenoy, W. Nicholls,
//     "Efficient minimum spanning tree construction without Delaunay triangulation,"
//     Information Processing Letters, 81(5), 271-276, 2002.
template <typename T>
std::vector<std::tuple<T, int, int>> manhattan_mst(std::vector<T> xs, std::vector<T> ys) {
    const int n = xs.size();
    std::vector<int> idx(n);
    std::iota(idx.begin(), idx.end(), 0);
    std::vector<std::tuple<T, int, int>> ret;
    for (int s = 0; s < 2; s++) {
        for (int t = 0; t < 2; t++) {
            auto cmp = [&](int i, int j) { return xs[i] + ys[i] < xs[j] + ys[j]; };
            std::sort(idx.begin(), idx.end(), cmp);
            std::map<T, int> sweep;
            for (int i : idx) {
                for (auto it = sweep.lower_bound(-ys[i]); it != sweep.end(); it = sweep.erase(it)) {
                    int j = it->second;
                    if (xs[i] - xs[j] < ys[i] - ys[j]) break;
                    ret.emplace_back(std::abs(xs[i] - xs[j]) + std::abs(ys[i] - ys[j]), i, j);
                }
                sweep[-ys[i]] = i;
            }
            std::swap(xs, ys);
        }
        for (auto &x : xs) x = -x;
    }
    std::sort(ret.begin(), ret.end());
    return ret;
}
#line 2 "graph/manhattan_mst.hpp"
#include <algorithm>
#include <map>
#include <numeric>
#include <tuple>
#include <vector>

// CUT begin
// Manhattan MST: 二次元平面上の頂点たちのマンハッタン距離による minimum spanning tree の O(N) 本の候補辺を列挙
// Complexity: O(N log N)
// output: [(weight_uv, u, v), ...]
// Verified: https://judge.yosupo.jp/problem/manhattanmst, https://www.codechef.com/problems/HKRMAN
// Reference:
// [1] H. Zhou, N. Shenoy, W. Nicholls,
//     "Efficient minimum spanning tree construction without Delaunay triangulation,"
//     Information Processing Letters, 81(5), 271-276, 2002.
template <typename T>
std::vector<std::tuple<T, int, int>> manhattan_mst(std::vector<T> xs, std::vector<T> ys) {
    const int n = xs.size();
    std::vector<int> idx(n);
    std::iota(idx.begin(), idx.end(), 0);
    std::vector<std::tuple<T, int, int>> ret;
    for (int s = 0; s < 2; s++) {
        for (int t = 0; t < 2; t++) {
            auto cmp = [&](int i, int j) { return xs[i] + ys[i] < xs[j] + ys[j]; };
            std::sort(idx.begin(), idx.end(), cmp);
            std::map<T, int> sweep;
            for (int i : idx) {
                for (auto it = sweep.lower_bound(-ys[i]); it != sweep.end(); it = sweep.erase(it)) {
                    int j = it->second;
                    if (xs[i] - xs[j] < ys[i] - ys[j]) break;
                    ret.emplace_back(std::abs(xs[i] - xs[j]) + std::abs(ys[i] - ys[j]), i, j);
                }
                sweep[-ys[i]] = i;
            }
            std::swap(xs, ys);
        }
        for (auto &x : xs) x = -x;
    }
    std::sort(ret.begin(), ret.end());
    return ret;
}
Back to top page