This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://judge.yosupo.jp/problem/manhattanmst"
#include <iostream>
#include "C++/graph/mst/kruskal.hpp"
#include "C++/graph/mst/manhattan.hpp"
int main() {
int n;
std::cin >> n;
std::vector<int> x(n), y(n);
for(int i = 0; i < n; ++i) {
std::cin >> x[i] >> y[i];
}
const auto ans = man::kruskal(man::manhattan(x, y), n);
std::cout << ans.cost << '\n';
for(const auto &e: ans.tree) {
std::cout << e.src << ' ' << e.to << '\n';
}
}
#line 1 "test/manhattan.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/manhattanmst"
#include <iostream>
#line 2 "C++/graph/mst/kruskal.hpp"
#include <vector>
#line 2 "C++/graph/mst/MST.hpp"
#line 2 "C++/graph/edge.hpp"
#ifndef EDGE
#define EDGE
#endif
namespace man {
struct edge {
int src, to, id;
long long cost;
edge(){}
edge(const int src_, const int to_, const int id_ = -1, const long long cost_ = 0): src(src_), to(to_), id(id_), cost(cost_){}
constexpr inline operator int() const noexcept { return to; }
};
}
/**
* @brief Edge
*/
#line 5 "C++/graph/mst/MST.hpp"
struct MST {
std::vector<man::edge> tree;
long long cost;
};
/**
* @brief 最小全域木
*/
#line 2 "C++/ds/uf/UnionFind.hpp"
#include <cassert>
#line 5 "C++/ds/uf/UnionFind.hpp"
#include <algorithm>
namespace man {
struct UnionFind {
protected:
std::vector<int> par;
public:
UnionFind(const int n): par(n, -1){}
inline int operator[](int i) noexcept {
while(par[i] >= 0) {
const int p = par[par[i]];
if(p < 0) return par[i];
i = par[i] = p;
}
return i;
}
inline bool unite(int x, int y) noexcept {
x = (*this)[x], y = (*this)[y];
if(x == y) return false;
if(-par[x] < -par[y]) {
std::swap(x, y);
}
par[x] += par[y], par[y] = x;
return true;
}
inline int size(const int x) noexcept {
return -par[(*this)[x]];
}
inline int size() const noexcept { return par.size(); }
inline std::vector<std::vector<int>> groups() noexcept {
const int n = std::ssize(par);
std::vector<std::vector<int>> res(n);
for(int i = 0; i < n; ++i) {
res[(*this)[i]].emplace_back(i);
}
const auto it = std::ranges::remove_if(res, [&](const std::vector<int> &v){ return v.empty(); });
res.erase(it.begin(), it.end());
return res;
}
};
inline bool is_bipartite(UnionFind uf) noexcept {
assert(uf.size() % 2 == 0);
const int n = uf.size() / 2;
bool ok = true;
for(int i = 0; i < n; ++i) {
ok &= uf[i] != uf[i + n];
}
return ok;
}
}
/**
* @brief UnionFind
* @see https://github.com/maspypy/library/blob/main/ds/unionfind/unionfind.hpp
*/
#line 6 "C++/graph/mst/kruskal.hpp"
namespace man {
inline MST kruskal(std::vector<edge> edges, const int n) noexcept {
std::ranges::sort(edges, [&](const edge &e, const edge &f) -> bool { return e.cost < f.cost; });
UnionFind uf(n);
std::vector<edge> e;
long long ret = 0;
for(const auto &ed: edges) {
if(uf.unite(ed.src, ed)) {
e.emplace_back(ed);
ret += ed.cost;
}
}
return {e, ret};
}
}
/**
* @brief Kruskal法
*/
#line 2 "C++/graph/mst/manhattan.hpp"
#line 4 "C++/graph/mst/manhattan.hpp"
#include <map>
#include <numeric>
#include <ranges>
#line 8 "C++/graph/mst/manhattan.hpp"
namespace man {
template <std::integral T> inline std::vector<edge> manhattan(std::vector<T> x, std::vector<T> y) noexcept {
assert(std::ssize(x) == std::ssize(y));
std::vector<edge> ret;
std::vector<int> id(std::ssize(x));
std::iota(id.begin(), id.end(), 0);
for([[maybe_unused]] const auto _: std::views::iota(0, 2)) {
for([[maybe_unused]] const auto _: std::views::iota(0, 2)) {
std::ranges::sort(id, [&](const int i, const int j) -> bool { return x[i] + y[i] < x[j] + y[j]; });
std::map<T, int> idx;
for(const auto i: id) {
for(auto it = idx.lower_bound(-y[i]); it != idx.end(); it = idx.erase(it)) {
const int j = it->second;
if(x[i] - x[j] < y[i] - y[j]) {
break;
}
ret.emplace_back(i, j, -1, std::abs(x[i] - x[j]) + std::abs(y[i] - y[j]));
}
idx[-y[i]] = i;
}
x.swap(y);
}
for(const auto i: std::views::iota(0, std::ssize(x))) {
x[i] *= -1;
}
}
return ret;
}
}
/**
* @brief Manhattan MST
* @see https://ei1333.github.io/library/graph/mst/manhattan-mst.hpp
*/
#line 5 "test/manhattan.test.cpp"
int main() {
int n;
std::cin >> n;
std::vector<int> x(n), y(n);
for(int i = 0; i < n; ++i) {
std::cin >> x[i] >> y[i];
}
const auto ans = man::kruskal(man::manhattan(x, y), n);
std::cout << ans.cost << '\n';
for(const auto &e: ans.tree) {
std::cout << e.src << ' ' << e.to << '\n';
}
}