题面
解法
可以考虑kd-tree,但是我并不会……
- 对于每一个 i i i,我们就是要求 m a x ( ∣ x [ i ] − x [ j ] ∣ + ∣ y [ i ] − y [ j ] ∣ ) max(|x[i]-x[j]|+|y[i]-y[j]|) max(∣x[i]−x[j]∣+∣y[i]−y[j]∣), m i n min min类似
- 考虑分 4 4 4种情况,就是将绝对值拆开
- 不妨只考虑 x [ j ] ≤ x [ i ] x[j]≤x[i] x[j]≤x[i]且 y [ j ] ≤ y [ i ] y[j]≤y[i] y[j]≤y[i]的情况,其他3种情况是类似的
- 发现将绝对值展开后为 ( x [ i ] + y [ i ] ) − ( x [ j ] + y [ j ] ) (x[i]+y[i])-(x[j]+y[j]) (x[i]+y[i])−(x[j]+y[j]),那么我们按照 x x x从小到大排序,在 x x x相同的时候按照 y y y从小到大排
- 然后我们枚举 i i i,强制 j < i j<i j<i,然后用线段树维护满足 y [ j ] y[j] y[j]在区间 [ 1 , y [ i ] ] [1,y[i]] [1,y[i]]的 x [ j ] + y [ j ] x[j]+y[j] x[j]+y[j]的最小值
- 可以发现,即使在这种情况下 j j j可能不会被 i i i统计到,但是在其他情况中 j j j一定会被 i i i统计到,所以算法是正确的
- 其实不一定要用线段树,似乎树状数组也可以完成这个工作
- 时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
代码
#include <bits/stdc++.h>
#define inf 1 << 29
#define N 200010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Point {
int x, y, id;
} a[N];
struct SegmentTree {
struct Node {
int lc, rc, mx, mn;
} t[N * 4];
int tot;
void Clear() {tot = 0, memset(t, 0, sizeof(t));}
void ins(int &k, int l, int r, int x, int v) {
if (!k) k = ++tot, t[k].mn = inf, t[k].mx = -inf;
chkmin(t[k].mn, v), chkmax(t[k].mx, v);
if (l == r) return; int mid = (l + r) >> 1;
if (x <= mid) ins(t[k].lc, l, mid, x, v);
else ins(t[k].rc, mid + 1, r, x, v);
}
pair <int, int> query(int k, int l, int r, int L, int R) {
if (!k) return make_pair(-inf, inf);
if (L <= l && r <= R) return make_pair(t[k].mx, t[k].mn);
int mid = (l + r) >> 1;
if (R <= mid) return query(t[k].lc, l, mid, L, R);
if (L > mid) return query(t[k].rc, mid + 1, r, L, R);
pair <int, int> tx = query(t[k].lc, l, mid, L, mid), ty = query(t[k].rc, mid + 1, r, mid + 1, R);
return make_pair(max(tx.first, ty.first), min(tx.second, ty.second));
}
} T;
bool cmp1(Point a, Point b) {return (a.x == b.x) ? a.y < b.y : a.x < b.x;}
bool cmp2(Point a, Point b) {return (a.x == b.x) ? a.y > b.y : a.x < b.x;}
bool cmp3(Point a, Point b) {return (a.x == b.x) ? a.y < b.y : a.x > b.x;}
bool cmp4(Point a, Point b) {return (a.x == b.x) ? a.y > b.y : a.x > b.x;}
int tx[N], mx[N], mn[N];
int main() {
int n, len = 0; read(n);
for (int i = 1; i <= n; i++)
read(a[i].x), read(a[i].y), tx[++len] = a[i].x, tx[++len] = a[i].y, a[i].id = i;
sort(tx + 1, tx + len + 1); len = unique(tx + 1, tx + len + 1) - tx - 1;
map <int, int> h;
for (int i = 1; i <= len; i++) h[tx[i]] = i;
for (int i = 1; i <= n; i++) a[i].x = h[a[i].x], a[i].y = h[a[i].y];
sort(a + 1, a + n + 1, cmp1), T.Clear(); int rt = 0;
for (int i = 1; i <= n; i++) mx[i] = -inf, mn[i] = inf;
for (int i = 1; i <= n; i++) {
pair <int, int> tmp = T.query(rt, 1, len, 1, a[i].y);
chkmax(mx[a[i].id], tx[a[i].x] + tx[a[i].y] - tmp.second);
chkmin(mn[a[i].id], tx[a[i].x] + tx[a[i].y] - tmp.first);
T.ins(rt, 1, len, a[i].y, tx[a[i].x] + tx[a[i].y]);
}
sort(a + 1, a + n + 1, cmp2), T.Clear(); rt = 0;
for (int i = 1; i <= n; i++) {
pair <int, int> tmp = T.query(rt, 1, len, a[i].y, len);
chkmax(mx[a[i].id], tx[a[i].x] - tx[a[i].y] - tmp.second);
chkmin(mn[a[i].id], tx[a[i].x] - tx[a[i].y] - tmp.first);
T.ins(rt, 1, len, a[i].y, tx[a[i].x] - tx[a[i].y]);
}
sort(a + 1, a + n + 1, cmp3), T.Clear(); rt = 0;
for (int i = 1; i <= n; i++) {
pair <int, int> tmp = T.query(rt, 1, len, 1, a[i].y);
chkmax(mx[a[i].id], -tx[a[i].x] + tx[a[i].y] - tmp.second);
chkmin(mn[a[i].id], -tx[a[i].x] + tx[a[i].y] - tmp.first);
T.ins(rt, 1, len, a[i].y, -tx[a[i].x] + tx[a[i].y]);
}
sort(a + 1, a + n + 1, cmp4), T.Clear(), rt = 0;
for (int i = 1; i <= n; i++) {
pair <int, int> tmp = T.query(rt, 1, len, a[i].y, len);
chkmax(mx[a[i].id], -tx[a[i].x] - tx[a[i].y] - tmp.second);
chkmin(mn[a[i].id], -tx[a[i].x] - tx[a[i].y] - tmp.first);
T.ins(rt, 1, len, a[i].y, -tx[a[i].x] - tx[a[i].y]);
}
int ans = inf;
for (int i = 1; i <= n; i++)
chkmin(ans, mx[i] - mn[i]);
cout << ans << "\n";
return 0;
}