1. 程式人生 > >bzoj 1941 [Sdoi2010]Hide and Seek 線段樹/kd-tree

bzoj 1941 [Sdoi2010]Hide and Seek 線段樹/kd-tree

題面

題目傳送門

解法

可以考慮kd-tree,但是我並不會……

  • 對於每一個ii,我們就是要求max(x[i]x[j]+y[i]y[j])max(|x[i]-x[j]|+|y[i]-y[j]|)minmin類似
  • 考慮分44種情況,就是將絕對值拆開
  • 不妨只考慮x[j]x[i]x[j]≤x[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]),那麼我們按照xx從小到大排序,在xx相同的時候按照yy從小到大排
  • 然後我們列舉ii,強制j<ij<i,然後用線段樹維護滿足y[j]y[j]在區間[1,y[i]][1,y[i]]x[j]+y[j]x[j]+y[j]的最小值
  • 可以發現,即使在這種情況下jj可能不會被ii統計到,但是在其他情況中jj一定會被ii統計到,所以演算法是正確的
  • 其實不一定要用線段樹,似乎樹狀陣列也可以完成這個工作
  • 時間複雜度:O(nlogn)O(n\log n)

程式碼

#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; }