【BZOJ】【1941】【SDOI2010】Hide and Seek
KD-Tree
一开始看错题了
其实是:给定n个点,从中找一个点,使得其他所有点到它距离的最大值与最小值之差最小。
利用KD-Tree暴力求出每个点的答案(找离它最近的点以及最远的点(当然只关心距离))
然后……两个过程分开写……
注意一下最近的点的距离不能是0(然而我一开始用 if (o==tmp) return INF; 就WA了……)(这里o是当前搜索到的点,tmp是枚举的起始点)
1 /************************************************************** 2 Problem: 1941 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:1484 ms 7 Memory:16900 kb 8 ****************************************************************/ 9 10 //BZOJ 1941 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 #define pb push_back 20 using namespace std; 21 typedef long long LL; 22 inline int getint(){ 23 int r=1,v=0; char ch=getchar(); 24 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 25 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 26 return r*v; 27 } 28 const int N=500010,INF=1e9; 29 /*******************template********************/ 30 31 struct node{ 32 int d[2],mn[2],mx[2],l,r; 33 int& operator [] (int x){return d[x];} 34 void read(){d[0]=getint(); d[1]=getint();} 35 }t[N]; 36 int n,m,D,root,tmp,ask_mx,ask_mn; 37 bool operator < (node a,node b){return a[D]<b[D];} 38 #define L t[o].l 39 #define R t[o].r 40 #define mid (l+r>>1) 41 void Push_up(int o){ 42 F(i,0,1){ 43 t[o].mn[i]=min(t[o].mn[i],min(t[L].mn[i],t[R].mn[i])); 44 t[o].mx[i]=max(t[o].mx[i],max(t[L].mx[i],t[R].mx[i])); 45 } 46 } 47 48 int build(int l,int r,int dir){ 49 D=dir; 50 nth_element(t+l,t+mid,t+r+1); 51 int o=mid; 52 F(i,0,1) t[o].mn[i]=t[o].mx[i]=t[o][i]; 53 if (l<mid) L=build(l,mid-1,dir^1); 54 if (mid<r) R=build(mid+1,r,dir^1); 55 Push_up(o); 56 return o; 57 } 58 59 int dis(int a){return abs(t[a][0]-t[tmp][0])+abs(t[a][1]-t[tmp][1]);} 60 int calc_mn(int o){ 61 if (!o) return INF; 62 int ans=0; 63 F(i,0,1) ans+=max(0,t[o].mn[i]-t[tmp][i]); 64 F(i,0,1) ans+=max(0,t[tmp][i]-t[o].mx[i]); 65 return ans; 66 } 67 68 void query_mn(int o){ 69 if (!o) return; 70 int dl=calc_mn(L),dr=calc_mn(R),d0=dis(o); 71 if (d0) ask_mn=min(ask_mn,d0); 72 if (dl<dr){ 73 if (dl<ask_mn) query_mn(L); 74 if (dr<ask_mn) query_mn(R); 75 }else{ 76 if (dr<ask_mn) query_mn(R); 77 if (dl<ask_mn) query_mn(L); 78 } 79 } 80 81 int calc_mx(int o){ 82 if (!o) return -INF; 83 int ans=0; 84 F(i,0,1) ans+=max(abs(t[o].mn[i]-t[tmp][i]),abs(t[o].mx[i]-t[tmp][i])); 85 return ans; 86 } 87 void query_mx(int o){ 88 if (!o) return; 89 int dl=calc_mx(L),dr=calc_mx(R),d0=dis(o); 90 ask_mx=max(ask_mx,d0); 91 if (dl>dr){ 92 if (dl>ask_mx) query_mx(L); 93 if (dr>ask_mx) query_mx(R); 94 }else{ 95 if (dr>ask_mx) query_mx(R); 96 if (dl>ask_mx) query_mx(L); 97 } 98 } 99 100 int main(){ 101 #ifndef ONLINE_JUDGE 102 freopen("1941.in","r",stdin); 103 freopen("1941.out","w",stdout); 104 #endif 105 n=getint(); 106 F(i,1,n) t[i].read(); 107 F(i,0,1) t[0].mn[i]=INF,t[0].mx[i]=-INF; 108 root=build(1,n,1); 109 int ans=INF; 110 F(i,1,n){ 111 ask_mn=INF; ask_mx=-INF; 112 tmp=i; 113 query_mn(root); 114 query_mx(root); 115 // printf("%d %d\n",ask_mx,ask_mn); 116 ans=min(ans,ask_mx-ask_mn); 117 } 118 printf("%d\n",ans); 119 return 0; 120 }
1941: [Sdoi2010]Hide and Seek
Time Limit: 16 Sec Memory Limit: 162 MBSubmit: 385 Solved: 213
[Submit][Status][Discuss]
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
0 0
1 0
0 1
1 1
Sample Output
HINT
对于30%的数据,N<=1000 对于100%的数据,N<=500000,0<=X,Y<=10^8 保证数据没有重点保证N>=2