領域を縦と横に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; }