|
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3706
/**//* 题意: 给定N(N <= 100000)个点,要求找到任意一个点的最近点,点的距离定义如下: Distance (A, B) = max (|Ax – Bx|, |Ay – By|),求出所有点的Distance和。
解法: 二维线段树
思路: 我的做法是利用二维线段树的二维区间求和,首先数字太大,需要离散化,然后 将所有数字插入到离散后的二维线段树区间,二维线段树维护一个Sum域,表示该二维 区间插入过的数字总和,然后对于每个点,二分枚举和它最近的点的距离,根据这个 距离找到最大的被这个距离包含的并且在二维线段树管辖范围的二维区间,查询那段 区间的Sum值,如果Sum值大于1的话说明这个范围不止一个点,于是可以缩小枚举的范 围,直到找到最小的枚举值,就是这个点的最近点,总的复杂度O(nlog(n)log(n))。 这里需要注意的是,二维区间的Sum和统计和插入点的时候处理不好可能会在同一 区间插入多次或者统计多次,这和区间最值有所不同,需要特殊处理二维区间的某一维 的长度为1的情况。 */ #include <iostream> #include <cmath> #include <algorithm> using namespace std;
#define maxn 200010 #define eps 1e-6 #define maxaxis 1000000000 #define ll __int64 typedef int Type;
Type bin[maxn]; int size, tot;
int B(Type val) { int l = 0; int r = tot-1; while(l <= r) { int m = (l + r) >> 1; if(bin[m] == val) return m; if(val > bin[m]) { l = m + 1; }else r = m - 1; } }
struct point { int x, y; int _ix, _iy; }P[maxn];
struct Tree { int son[4]; Type Sum;
void clear() { Sum = 0; for(int i = 0; i < 4; i++) son[i] = -1; } }T[maxn*6]; int root, all;
void Insert(int& root, int x, int y, int lx, int rx, int ly, int ry) { if(x > rx || x < lx || y > ry || y < ly) return ;
if(root == -1) { root = all++; T[root].clear(); }
if(lx == rx && x == lx && y == ly && ly == ry) { T[root].Sum ++; return ; }
int midx0 = (lx + rx) >> 1; int midy0 = (ly + ry) >> 1; int midx1 = (lx==rx) ? midx0 : midx0 + 1; int midy1 = (ly==ry) ? midy0 : midy0 + 1;
if(lx == rx) { Insert(T[root].son[0], x, y, lx, midx0, ly, midy0); Insert(T[root].son[1], x, y, lx, midx0, midy1, ry); }else if(ly == ry) { Insert(T[root].son[1], x, y, lx, midx0, midy1, ry); Insert(T[root].son[2], x, y, midx1, rx, ly, midy0); }else { Insert(T[root].son[0], x, y, lx, midx0, ly, midy0); Insert(T[root].son[1], x, y, lx, midx0, midy1, ry); Insert(T[root].son[2], x, y, midx1, rx, ly, midy0); Insert(T[root].son[3], x, y, midx1, rx, midy1, ry); }
int i; T[root].Sum = 0; for(i = 0; i < 4; i++) { if(T[root].son[i] != -1) { T[root].Sum += T[ T[root].son[i] ].Sum; } } }
void Query(int root, int x0, int x1, int y0, int y1, int lx, int rx, int ly, int ry, Type& Num) { if(x0 > rx || x1 < lx || y0 > ry || y1 < ly || root == -1) return ;
if(Num > 1) return ;
if(x0 <= lx && rx <= x1 && y0 <= ly && ry <= y1) { Num += T[root].Sum; return ; }
int midx0 = (lx + rx) >> 1; int midy0 = (ly + ry) >> 1; int midx1 = (lx==rx) ? midx0 : midx0 + 1; int midy1 = (ly==ry) ? midy0 : midy0 + 1; if(lx == rx) { Query(T[root].son[0], x0, x1, y0, y1, lx, midx0, ly, midy0, Num); Query(T[root].son[1], x0, x1, y0, y1, lx, midx0, midy1, ry, Num); }else if(ly == ry) { Query(T[root].son[1], x0, x1, y0, y1, lx, midx0, midy1, ry, Num); Query(T[root].son[2], x0, x1, y0, y1, midx1, rx, ly, midy0, Num); }else { Query(T[root].son[0], x0, x1, y0, y1, lx, midx0, ly, midy0, Num); Query(T[root].son[1], x0, x1, y0, y1, lx, midx0, midy1, ry, Num); Query(T[root].son[2], x0, x1, y0, y1, midx1, rx, ly, midy0, Num); Query(T[root].son[3], x0, x1, y0, y1, midx1, rx, midy1, ry, Num); } }
int LargeThan(int val, int pre) { int l = 0; int r = pre; int ans = l; while(l <= r) { int m = (l + r) >> 1; if(val <= bin[m]) { r = m - 1; ans = m; }else l = m + 1; } return ans; }
int LessThan(int val, int pre) { int l = pre; int r = tot - 1; int ans = r; while(l <= r) { int m = (l + r) >> 1; if(val >= bin[m]) { l = m + 1; ans = m; }else r = m - 1; } return ans; }
int Process(int idx, int dis) { int xleft = LargeThan( P[idx].x - dis, P[idx]._ix ); int yleft = LargeThan( P[idx].y - dis, P[idx]._iy ); int xright = LessThan( P[idx].x + dis, P[idx]._ix ); int yright = LessThan( P[idx].y + dis, P[idx]._iy ); int Num = 0; Query(root, xleft, xright, yleft, yright, 0, tot-1, 0, tot-1, Num); return Num; }
int n; int main() { int i; int Max;
while(scanf("%d", &n) != EOF) { size = 0; tot = 0; all = 0; Max = 0; for(i = 0; i < n; i++) { scanf("%d %d", &P[i].x, &P[i].y); bin[ size++ ] = P[i].x; bin[ size++ ] = P[i].y; if(P[i].x > Max) Max = P[i].x; if(P[i].y > Max) Max = P[i].y; } sort(bin, bin + size); for(i = 0; i < size; i++) { if(i == 0 || bin[i] != bin[i-1]) bin[tot++] = bin[i]; } root = -1; for(i = 0; i < n; i++) { P[i]._ix = B(P[i].x); P[i]._iy = B(P[i].y); Insert(root, P[i]._ix, P[i]._iy, 0, tot-1, 0, tot-1); }
ll ans = 0; for(i = 0; i < n; i++) { int l = 0; int r = Max; int dis = 0; while(l <= r) { int m = (l + r) >> 1; if(Process(i, m) > 1) { r = m - 1; dis = m; }else l = m + 1; } ans += dis; } printf("%I64d\n", ans); } return 0; }
|