1. 程式人生 > >BZOJ_1941_[Sdoi2010]Hide and Seek_KDtree

BZOJ_1941_[Sdoi2010]Hide and Seek_KDtree

-s 水平 電話 operator tdi 寂寞 多少 light med

BZOJ_1941_[Sdoi2010]Hide and Seek_KDtree

Description

小豬iPig在PKU剛上完了無聊的豬性代數課,天資聰慧的iPig被這門對他來說無比簡單的課弄得非常寂寞,為了消除寂寞感,他決定和他的好朋友giPi(雞皮)玩一個更加寂寞的遊戲---捉迷藏。 但是,他們覺得,玩普通的捉迷藏沒什麽意思,還是不夠寂寞,於是,他們決定玩寂寞無比的螃蟹版捉迷藏,顧名思義,就是說他們在玩遊戲的時候只能沿水平或垂直方向走。一番寂寞的剪刀石頭布後,他們決定iPig去捉giPi。由於他們都很熟悉PKU的地形了,所以giPi只會躲在PKU內n個隱秘地點,顯然iPig也只會在那n個地點內找giPi。遊戲一開始,他們選定一個地點,iPig保持不動,然後giPi用30秒的時間逃離現場(顯然,giPi不會呆在原地)。然後iPig會隨機地去找giPi,直到找到為止。由於iPig很懶,所以他到總是走最短的路徑,而且,他選擇起始點不是隨便選的,他想找一個地點,使得該地點到最遠的地點和最近的地點的距離差最小。iPig現在想知道這個距離差最小是多少。 由於iPig現在手上沒有電腦,所以不能編程解決這個如此簡單的問題,所以他馬上打了個電話,要求你幫他解決這個問題。iPig告訴了你PKU的n個隱秘地點的坐標,請你編程求出iPig的問題。

Input

第一行輸入一個整數N 第2~N+1行,每行兩個整數X,Y,表示第i個地點的坐標

Output

一個整數,為距離差的最小值。

Sample Input

4
0 0
1 0
0 1
1 1

Sample Output

1

HINT

對於30%的數據,N<=1000 對於100%的數據,N<=500000,0<=X,Y<=10^8 保證數據沒有重點保證N>=2


枚舉一個點,在kdtree中查離這個點最遠的點和最近的點。

最元的點的估價就是橫縱坐標最大的絕對值之和。

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 500050
#define ls ch[p][0]
#define rs ch[p][1]
#define _max(x,y) ((x)>(y)?(x):(y))
#define _min(x,y) ((x)<(y)?(x):(y))
#define inf 0x3f3f3f3f
int ch[N][2],mx[N][2],mn[N][2],now,ans1,ans2,n;
struct Point {
	int p[2];
	bool operator < (const Point &x) const {
		return p[now]==x.p[now]?p[!now]<x.p[!now]:p[now]<x.p[now];
	}
}a[N];
inline char nc() {
	static char buf[100000],*p1,*p2;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
	int x=0; char s=nc();
	while(s<‘0‘||s>‘9‘) s=nc();
	while(s>=‘0‘&&s<=‘9‘) x=(x<<3)+(x<<1)+s-‘0‘,s=nc();
	return x;	
}
int Abs(int x) {return x>0?x:-x;}
void pushup(int p,int x) {
	mx[p][0]=_max(mx[p][0],mx[x][0]);
	mn[p][0]=_min(mn[p][0],mn[x][0]);
	mx[p][1]=_max(mx[p][1],mx[x][1]);
	mn[p][1]=_min(mn[p][1],mn[x][1]);
}
int build(int l,int r,int type) {
	int mid=(l+r)>>1; now=type;
	nth_element(a+l,a+mid,a+r+1);
	mx[mid][0]=mn[mid][0]=a[mid].p[0];
	mx[mid][1]=mn[mid][1]=a[mid].p[1];
	if(l<mid) ch[mid][0]=build(l,mid-1,!type),pushup(mid,ch[mid][0]);
	if(r>mid) ch[mid][1]=build(mid+1,r,!type),pushup(mid,ch[mid][1]);
	return mid;
}
int dismin(int x,int y,int p) {
	return _max(mn[p][0]-x,0)+_max(x-mx[p][0],0)+_max(mn[p][1]-y,0)+_max(y-mx[p][1],0);
}
int dismax(int x,int y,int p) {
	return max(Abs(x-mx[p][0]),Abs(x-mn[p][0]))+max(Abs(y-mx[p][1]),Abs(y-mn[p][1]));
}
void query_min(int x,int y,int p) {
	int re=Abs(x-a[p].p[0])+Abs(y-a[p].p[1]),dl,dr;
	if(re&&re<ans1) ans1=re;
	dl=ls?dismin(x,y,ls):inf;
	dr=rs?dismin(x,y,rs):inf;
	if(dl<dr) {
		if(dl<ans1) query_min(x,y,ls);
		if(dr<ans1) query_min(x,y,rs);
	}else {
		if(dr<ans1) query_min(x,y,rs);
		if(dl<ans1) query_min(x,y,ls);
	}
}
void query_max(int x,int y,int p) {
	int re=Abs(x-a[p].p[0])+Abs(y-a[p].p[1]),dl,dr;
	if(re>ans2) ans2=re;
	dl=ls?dismax(x,y,ls):-inf;
	dr=rs?dismax(x,y,rs):-inf;
	if(dl>dr) {
		if(dl>ans2) query_max(x,y,ls);
		if(dr>ans2) query_max(x,y,rs);
	}else {
		if(dr>ans2) query_max(x,y,rs);
		if(dl>ans2) query_max(x,y,ls);
	}
}
int main() {
	n=rd();
	int i;
	for(i=1;i<=n;i++) a[i].p[0]=rd(),a[i].p[1]=rd();
	int root=build(1,n,0);
	int ans3=inf;
	for(i=1;i<=n;i++) ans1=inf,ans2=0,query_min(a[i].p[0],a[i].p[1],root),query_max(a[i].p[0],a[i].p[1],root),ans3=_min(ans3,ans2-ans1);
	printf("%d\n",ans3);
}

BZOJ_1941_[Sdoi2010]Hide and Seek_KDtree