領域を縦と横に2分割して、4つの領域に分ける。
縦は2種類の点を分ける様なX軸に垂直な直線で分割し、横はそれっぽい直線で分割する。
横方向に隣合う領域同士の近い点か、斜めの領域同士の点から最近点を探す。
互いに斜めな領域同士の点の移動は、分割に使った縦と横の線の交点を通る様な移動を考える。
あとは、点の数が少なくなるまで横の分割を繰り返す。
- #include <algorithm>
- #include <complex>
- #include <deque>
- #include <functional>
- #include <iomanip>
- #include <iostream>
- #include <map>
- #include <numeric>
- #include <queue>
- #include <set>
- #include <sstream>
- #include <stack>
- #include <string>
- #include <utility>
- #include <vector>
- #include <cassert>
- #include <climits>
- #include <cmath>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #define REP(i, n) for(int i=0; i<(int)n; ++i)
- #define FOR(i, c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
- #define ALL(c) (c).begin(),(c).end()
- #define each(i, c) FOR(i, c)
- #define unless(cond) if (!(cond))
- using namespace std;
- typedef long long int lli;
- typedef unsigned long long ull;
- typedef complex<double> point;
- namespace std {
- inline
- bool operator < (const point& a, const point& b)
- {
- return a.imag () < b.imag();
- }
- };
- const int N = 100000 + 1;
- point A[N], B[N];
- const int inf = 1 << 28;
- inline
- int m_dist(const point& a, const point& b)
- {
- return abs(a.real() - b.real()) + abs(a.imag() - b.imag());
- }
- int conque(int begin_a, int end_a, int begin_b, int end_b, point P, int z)
- {
- int v = inf;
- int u = inf;
- for (int i = begin_a; i < end_a; ++i) {
- v = min(v, m_dist(A[i], P));
- }
- for (int i = begin_b; i < end_b; ++i) {
- u = min(u, m_dist(B[i], P));
- }
- return v + u;
- }
- int X;
- // [begin_x, end_x)
- int divide(int begin_a, int end_a, int begin_b, int end_b)
- {
- if (end_a - begin_a < 5 || end_b - begin_b < 5) {
- int ret = inf;
- for (int i = begin_a; i < end_a; ++i) {
- for (int j = begin_b; j < end_b; ++j) {
- ret = min(ret, m_dist(A[i], B[j]));
- }
- }
- return ret;
- }
- int min_I = min(A[begin_a].imag(), B[begin_b].imag());
- int max_I = min(A[end_a - 1].imag(), B[end_b - 1].imag());
- int Y = (double)rand() * (double)(max_I - min_I) / (double)(RAND_MAX) + min_I;
- point P(X, Y);
- int mid_a = lower_bound(A + begin_a, A + end_a, P) - A;
- int mid_b = lower_bound(B + begin_b, B + end_b, P) - B;
- int x = divide(begin_a, mid_a, begin_b, mid_b);
- int y = divide(mid_a, end_a, mid_b, end_b);
- int z = min(x, y);
- z = min(z, conque(begin_a, mid_a, mid_b, end_b, P, z));
- z = min(z, conque(mid_a, end_a, begin_b, mid_b, P, z));
- return z;
- }
- int main(int argc, char *argv[])
- {
- int tc;
- cin >> tc;
- while (tc--) {
- int n;
- cin >> n;
- for (int i = 0; i < n; ++i) {
- cin >> A[i].real() >> A[i].imag();
- }
- int m;
- cin >> m;
- for (int i = 0; i < m; ++i) {
- cin >> B[i].real() >> B[i].imag();
- }
- int mx = -1;
- for (int i = 0; i < n; ++i) {
- mx = max(mx, (int)A[i].real());
- }
- int mn = inf;
- for (int i = 0; i < m; ++i) {
- mn = min(mn, (int)B[i].real());
- }
- X = abs(mx - mn) / 2;
- sort(A, A + n);
- sort(B, B + m);
- cout << divide(0, n, 0, m) << endl;
- }
- return 0;
- }