【BZOJ1941】【SDOI2010】Hide and Seek

【题目链接】

【思路要点】

  • 用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;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/80055244