【题目链接】
【思路要点】
- 用KDTree做的话就是模板题了,时间复杂度\(O(N\sqrt{N})\)。
- 正解应该是分治。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 500005 #define INF 1e9 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } struct point {int x[2]; } p[MAXN]; int cmptype; bool cmp(point a, point b) { return a.x[cmptype] < b.x[cmptype] || a.x[cmptype] == b.x[cmptype] && a.x[cmptype ^ 1] < b.x[cmptype ^ 1]; } void chkmax(int &x, int y) { x = max(x, y); } void chkmin(int &x, int y) { x = min(x, y); } struct KD_Tree { int n, root, size, nowans; int lc[MAXN], rc[MAXN], type[MAXN]; point pos[MAXN], L[MAXN], R[MAXN], now; void update(int root) { L[root] = pos[root]; R[root] = pos[root]; if (lc[root]) { int tmp = lc[root]; chkmin(L[root].x[0], L[tmp].x[0]); chkmin(L[root].x[1], L[tmp].x[1]); chkmax(R[root].x[0], R[tmp].x[0]); chkmax(R[root].x[1], R[tmp].x[1]); } if (rc[root]) { int tmp = rc[root]; chkmin(L[root].x[0], L[tmp].x[0]); chkmin(L[root].x[1], L[tmp].x[1]); chkmax(R[root].x[0], R[tmp].x[0]); chkmax(R[root].x[1], R[tmp].x[1]); } } void build(int root, int l, int r, int t) { if (l == r) { pos[root] = p[l]; L[root] = p[l]; R[root] = p[l]; type[root] = t; return; } int mid = (l + r) / 2; cmptype = t; nth_element(p + l, p + mid, p + r + 1, cmp); pos[root] = p[mid]; type[root] = t; if (mid > l) { lc[root] = ++size; build(size, l, mid - 1, t ^ 1); } if (mid < r) { rc[root] = ++size; build(size, mid + 1, r, t ^ 1); } update(root); } void init(int x) { n = x; root = size = 1; build(size, 1, n, 0); } int dist(int root, point now) { return abs(pos[root].x[0] - now.x[0]) + abs(pos[root].x[1] - now.x[1]); } int distmax(int root, point now) { if (root == 0) return 0; int tx = max(abs(L[root].x[0] - now.x[0]), abs(R[root].x[0] - now.x[0])); int ty = max(abs(L[root].x[1] - now.x[1]), abs(R[root].x[1] - now.x[1])); return tx + ty; } int distmin(int root, point now) { if (root == 0) return INF; int ans = 0; if (now.x[0] <= L[root].x[0]) ans += L[root].x[0] - now.x[0]; if (now.x[0] >= R[root].x[0]) ans += now.x[0] - R[root].x[0]; if (now.x[1] <= L[root].x[1]) ans += L[root].x[1] - now.x[1]; if (now.x[1] >= R[root].x[1]) ans += now.x[1] - R[root].x[1]; return ans; } void querymax(int root) { int d = dist(root, now); chkmax(nowans, d); int ld = distmax(lc[root], now); int rd = distmax(rc[root], now); if (ld >= rd) { if (lc[root] && ld > nowans) querymax(lc[root]); if (rc[root] && rd > nowans) querymax(rc[root]); } else { if (rc[root] && rd > nowans) querymax(rc[root]); if (lc[root] && ld > nowans) querymax(lc[root]); } } int Querymax(point x) { now = x; nowans = 0; querymax(root); return nowans; } void querymin(int root) { int d = dist(root, now); if (d != 0) chkmin(nowans, d); int ld = distmin(lc[root], now); int rd = distmin(rc[root], now); if (ld <= rd) { if (lc[root] && ld < nowans) querymin(lc[root]); if (rc[root] && rd < nowans) querymin(rc[root]); } else { if (rc[root] && rd < nowans) querymin(rc[root]); if (lc[root] && ld < nowans) querymin(lc[root]); } } int Querymin(point x) { now = x; nowans = INF; querymin(root); return nowans; } } KDT; int main() { int n; read(n); for (int i = 1; i <= n; i++) read(p[i].x[0]), read(p[i].x[1]); KDT.init(n); int ans = INF; for (int i = 1; i <= n; i++) ans = min(ans, KDT.Querymax(p[i]) - KDT.Querymin(p[i])); cout << ans << endl; return 0; }