This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub maspypy/library
#include "geo/closest_pair.hpp"
#include "geo/base.hpp" #include "random/base.hpp" #include "random/shuffle.hpp" #include "ds/hashmap.hpp" #include "random/hash_pair.hpp" template <typename T> pair<int, int> closest_pair(vc<Point<T>> points) { int N = len(points); assert(N >= 2); HashMap<int> MP(N); vc<int> I(N); iota(all(I), 0); shuffle(I); points = rearrange(points, I); auto calc = [&](int i, int j) -> T { return (points[j] - points[i]).dot(points[j] - points[i]); }; T best = calc(0, 1); pair<int, int> res = {0, 1}; T w = sqrtl(best); vc<int> nxt(N, -1); auto insert = [&](int i) -> void { u64 k = hash_pair<ll>({points[i].x / w, points[i].y / w}); nxt[i] = MP.get(k, -1); MP[k] = i; }; auto query = [&](int i) -> bool { ll a = points[i].x / w; ll b = points[i].y / w; bool upd = 0; FOR(dx, -1, 2) FOR(dy, -1, 2) { u64 k = hash_pair<ll>({a + dx, b + dy}); int j = MP.get(k, -1); while (j != -1) { if (chmin(best, calc(i, j))) { upd = 1, res = {i, j}, w = sqrtl(best); } j = nxt[j]; } } return upd; }; if (best == T(0)) { res.fi = I[res.fi], res.se = I[res.se]; return res; } insert(0), insert(1); FOR(i, 2, N) { if (query(i)) { if (best == T(0)) break; MP.build(N); FOR(j, i) insert(j); } insert(i); } res.fi = I[res.fi], res.se = I[res.se]; return res; } pair<int, int> closest_pair_dc(vc<Point<ll>> point) { int N = len(point); assert(N >= 2); auto I = argsort(point); point = rearrange(point, I); ll best = -1; pair<int, int> best_pair = {-1, -1}; auto upd = [&](int i, int j) -> void { Point<ll> p = point[i] - point[j]; ll d = p.dot(p); if (best == -1 || best > d) { best = d, best_pair = {I[i], I[j]}; } }; upd(0, 1); auto dfs = [&](auto &dfs, int L, int R) -> vc<int> { // return: [L,R) を y について sort したもの if (R == L + 1) return {L}; int M = (L + R) / 2; vc<int> I0 = dfs(dfs, L, M); vc<int> I1 = dfs(dfs, M, R); vc<int> I; vc<int> near; int a = 0, b = 0; FOR(R - L) { int idx = [&]() -> int { if (a == len(I0)) return I1[b++]; if (b == len(I1)) return I0[a++]; int i = I0[a], j = I1[b]; if (point[i].y < point[j].y) { ++a; return i; } ++b; return j; }(); I.eb(idx); ll dx = point[M].x - point[idx].x; if (dx * dx > best) { continue; } FOR_R(k, len(near)) { int j = near[k]; ll dy = point[idx].y - point[j].y; if (best == 0 || dy * dy > best) break; upd(idx, j); } near.eb(idx); } return I; }; dfs(dfs, 0, N); return best_pair; }
#line 2 "geo/base.hpp" template <typename T> struct Point { T x, y; Point() : x(0), y(0) {} template <typename A, typename B> Point(A x, B y) : x(x), y(y) {} template <typename A, typename B> Point(pair<A, B> p) : x(p.fi), y(p.se) {} Point operator+=(const Point p) { x += p.x, y += p.y; return *this; } Point operator-=(const Point p) { x -= p.x, y -= p.y; return *this; } Point operator+(Point p) const { return {x + p.x, y + p.y}; } Point operator-(Point p) const { return {x - p.x, y - p.y}; } bool operator==(Point p) const { return x == p.x && y == p.y; } bool operator!=(Point p) const { return x != p.x || y != p.y; } Point operator-() const { return {-x, -y}; } Point operator*(T t) const { return {x * t, y * t}; } Point operator/(T t) const { return {x / t, y / t}; } bool operator<(Point p) const { if (x != p.x) return x < p.x; return y < p.y; } T dot(Point other) { return x * other.x + y * other.y; } T det(Point other) { return x * other.y - y * other.x; } double norm() { return sqrtl(x * x + y * y); } double angle() { return atan2(y, x); } Point rotate(double theta) { static_assert(!is_integral<T>::value); double c = cos(theta), s = sin(theta); return Point{c * x - s * y, s * x + c * y}; } }; #ifdef FASTIO template <typename T> void rd(Point<T> &p) { fastio::rd(p.x), fastio::rd(p.y); } template <typename T> void wt(Point<T> &p) { fastio::wt(p.x); fastio::wt(' '); fastio::wt(p.y); } #endif // A -> B -> C と進むときに、左に曲がるならば +1、右に曲がるならば -1 template <typename T> int ccw(Point<T> A, Point<T> B, Point<T> C) { T x = (B - A).det(C - A); if (x > 0) return 1; if (x < 0) return -1; return 0; } template <typename REAL, typename T, typename U> REAL dist(Point<T> A, Point<U> B) { REAL dx = REAL(A.x) - REAL(B.x); REAL dy = REAL(A.y) - REAL(B.y); return sqrt(dx * dx + dy * dy); } // ax+by+c template <typename T> struct Line { T a, b, c; Line(T a, T b, T c) : a(a), b(b), c(c) {} Line(Point<T> A, Point<T> B) { a = A.y - B.y, b = B.x - A.x, c = A.x * B.y - A.y * B.x; } Line(T x1, T y1, T x2, T y2) : Line(Point<T>(x1, y1), Point<T>(x2, y2)) {} template <typename U> U eval(Point<U> P) { return a * P.x + b * P.y + c; } template <typename U> T eval(U x, U y) { return a * x + b * y + c; } // 同じ直線が同じ a,b,c で表現されるようにする void normalize() { static_assert(is_same_v<T, int> || is_same_v<T, long long>); T g = gcd(gcd(abs(a), abs(b)), abs(c)); a /= g, b /= g, c /= g; if (b < 0) { a = -a, b = -b, c = -c; } if (b == 0 && a < 0) { a = -a, b = -b, c = -c; } } bool is_parallel(Line other) { return a * other.b - b * other.a == 0; } bool is_orthogonal(Line other) { return a * other.a + b * other.b == 0; } }; template <typename T> struct Segment { Point<T> A, B; Segment(Point<T> A, Point<T> B) : A(A), B(B) {} Segment(T x1, T y1, T x2, T y2) : Segment(Point<T>(x1, y1), Point<T>(x2, y2)) {} bool contain(Point<T> C) { T det = (C - A).det(B - A); if (det != 0) return 0; return (C - A).dot(B - A) >= 0 && (C - B).dot(A - B) >= 0; } Line<T> to_Line() { return Line(A, B); } }; template <typename REAL> struct Circle { Point<REAL> O; REAL r; Circle(Point<REAL> O, REAL r) : O(O), r(r) {} Circle(REAL x, REAL y, REAL r) : O(x, y), r(r) {} template <typename T> bool contain(Point<T> p) { REAL dx = p.x - O.x, dy = p.y - O.y; return dx * dx + dy * dy <= r * r; } }; #line 2 "random/base.hpp" u64 RNG_64() { static uint64_t x_ = uint64_t(chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count()) * 10150724397891781847ULL; x_ ^= x_ << 7; return x_ ^= x_ >> 9; } u64 RNG(u64 lim) { return RNG_64() % lim; } ll RNG(ll l, ll r) { return l + RNG_64() % (r - l); } #line 2 "random/shuffle.hpp" template <typename T> void shuffle(vc<T>& A) { FOR(i, len(A)) { int j = RNG(0, i + 1); if (i != j) swap(A[i], A[j]); } } #line 2 "ds/hashmap.hpp" // u64 -> Val template <typename Val> struct HashMap { // n は入れたいものの個数で ok HashMap(u32 n = 0) { build(n); } void build(u32 n) { u32 k = 8; while (k < n * 2) k *= 2; cap = k / 2, mask = k - 1; key.resize(k), val.resize(k), used.assign(k, 0); } // size を保ったまま. size=0 にするときは build すること. void clear() { used.assign(len(used), 0); cap = (mask + 1) / 2; } int size() { return len(used) / 2 - cap; } int index(const u64& k) { int i = 0; for (i = hash(k); used[i] && key[i] != k; i = (i + 1) & mask) {} return i; } Val& operator[](const u64& k) { if (cap == 0) extend(); int i = index(k); if (!used[i]) { used[i] = 1, key[i] = k, val[i] = Val{}, --cap; } return val[i]; } Val get(const u64& k, Val default_value) { int i = index(k); return (used[i] ? val[i] : default_value); } bool count(const u64& k) { int i = index(k); return used[i] && key[i] == k; } // f(key, val) template <typename F> void enumerate_all(F f) { FOR(i, len(used)) if (used[i]) f(key[i], val[i]); } private: u32 cap, mask; vc<u64> key; vc<Val> val; vc<bool> used; u64 hash(u64 x) { static const u64 FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); x += FIXED_RANDOM; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return (x ^ (x >> 31)) & mask; } void extend() { vc<pair<u64, Val>> dat; dat.reserve(len(used) / 2 - cap); FOR(i, len(used)) { if (used[i]) dat.eb(key[i], val[i]); } build(2 * len(dat)); for (auto& [a, b]: dat) (*this)[a] = b; } }; #line 2 "random/hash_pair.hpp" template <typename T> u64 hash_pair(pair<T, T> X) { static ll hash_base = 0; if (hash_base == 0) hash_base = RNG_64(); return hash_base * X.fi + X.se; } #line 6 "geo/closest_pair.hpp" template <typename T> pair<int, int> closest_pair(vc<Point<T>> points) { int N = len(points); assert(N >= 2); HashMap<int> MP(N); vc<int> I(N); iota(all(I), 0); shuffle(I); points = rearrange(points, I); auto calc = [&](int i, int j) -> T { return (points[j] - points[i]).dot(points[j] - points[i]); }; T best = calc(0, 1); pair<int, int> res = {0, 1}; T w = sqrtl(best); vc<int> nxt(N, -1); auto insert = [&](int i) -> void { u64 k = hash_pair<ll>({points[i].x / w, points[i].y / w}); nxt[i] = MP.get(k, -1); MP[k] = i; }; auto query = [&](int i) -> bool { ll a = points[i].x / w; ll b = points[i].y / w; bool upd = 0; FOR(dx, -1, 2) FOR(dy, -1, 2) { u64 k = hash_pair<ll>({a + dx, b + dy}); int j = MP.get(k, -1); while (j != -1) { if (chmin(best, calc(i, j))) { upd = 1, res = {i, j}, w = sqrtl(best); } j = nxt[j]; } } return upd; }; if (best == T(0)) { res.fi = I[res.fi], res.se = I[res.se]; return res; } insert(0), insert(1); FOR(i, 2, N) { if (query(i)) { if (best == T(0)) break; MP.build(N); FOR(j, i) insert(j); } insert(i); } res.fi = I[res.fi], res.se = I[res.se]; return res; } pair<int, int> closest_pair_dc(vc<Point<ll>> point) { int N = len(point); assert(N >= 2); auto I = argsort(point); point = rearrange(point, I); ll best = -1; pair<int, int> best_pair = {-1, -1}; auto upd = [&](int i, int j) -> void { Point<ll> p = point[i] - point[j]; ll d = p.dot(p); if (best == -1 || best > d) { best = d, best_pair = {I[i], I[j]}; } }; upd(0, 1); auto dfs = [&](auto &dfs, int L, int R) -> vc<int> { // return: [L,R) を y について sort したもの if (R == L + 1) return {L}; int M = (L + R) / 2; vc<int> I0 = dfs(dfs, L, M); vc<int> I1 = dfs(dfs, M, R); vc<int> I; vc<int> near; int a = 0, b = 0; FOR(R - L) { int idx = [&]() -> int { if (a == len(I0)) return I1[b++]; if (b == len(I1)) return I0[a++]; int i = I0[a], j = I1[b]; if (point[i].y < point[j].y) { ++a; return i; } ++b; return j; }(); I.eb(idx); ll dx = point[M].x - point[idx].x; if (dx * dx > best) { continue; } FOR_R(k, len(near)) { int j = near[k]; ll dy = point[idx].y - point[j].y; if (best == 0 || dy * dy > best) break; upd(idx, j); } near.eb(idx); } return I; }; dfs(dfs, 0, N); return best_pair; }