bzoj 1941 [Sdoi2010]Hide and Seek 线段树/kd-tree

题面

题目传送门

解法

可以考虑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 
#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;
}

你可能感兴趣的:(【OJ】BZOJ,【数据结构】线段树)