bzoj 1941: [Sdoi2010]Hide and Seek
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
思路: 最近在看一些和启发式有关的题目,无意间看到了kd树,就做了一下最近点对问题,然后学习了一下kd树,kd树确实是一个很奇妙的树,可以说是一个大暴力的写法吧,不过他可以为k维空间的信息,这个还是比较牛逼的。
在处理每个点的最近点问题和最远点问题的时候,用了一个估价函数,类似启发式搜索,把时间复杂度降低到了神奇的$O(nlogn)$,随机数据的前提,而且常数还是有点大的。
找了网上的一些资料学习kd树,发现要么讲的很复杂,那么讲的很简单,后来找到了清华的一个课件,终于看懂了。
kd树类似线段树,也和平衡树很像,所以可以处理很多问题。
K-D Tree 的重构 K-D Tree 替代树套树 K-D Tree 替代可持久化树套树 K-D Tree 替代重量平衡树套线段树维护凸包 练习:K-D Tree 优化 Dp
这些都是清华课件里面讲的东西,好像有点难,慢慢做了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const N=500000+100; 4 int const inf=1e9; 5 int x[N],y[N],cur,n,root; 6 struct node{ 7 int d[2],mx[2],my[2],ch[2]; 8 bool operator < ( const node &rhs) const{ 9 return d[cur]<rhs.d[cur]; 10 } 11 }p[N]; 12 struct kdtree{ 13 node t[N],T; 14 int ans; 15 void update(int mid){ 16 int l=t[mid].ch[0]; 17 int r=t[mid].ch[1]; 18 if(l){ 19 t[mid].mx[0]=min(t[mid].mx[0],t[l].mx[0]); 20 t[mid].mx[1]=max(t[mid].mx[1],t[l].mx[1]); 21 t[mid].my[0]=min(t[mid].my[0],t[l].my[0]); 22 t[mid].my[1]=max(t[mid].my[1],t[l].my[1]); 23 } 24 if(r){ 25 t[mid].mx[0]=min(t[mid].mx[0],t[r].mx[0]); 26 t[mid].mx[1]=max(t[mid].mx[1],t[r].mx[1]); 27 t[mid].my[0]=min(t[mid].my[0],t[r].my[0]); 28 t[mid].my[1]=max(t[mid].my[1],t[r].my[1]); 29 } 30 } 31 int build(int l,int r,int x){ 32 cur=x; 33 int mid=(l+r)/2; 34 nth_element(p+l,p+mid,p+r+1); 35 t[mid]=p[mid]; 36 t[mid].mx[0]=t[mid].mx[1]=t[mid].d[0]; 37 t[mid].my[0]=t[mid].my[1]=t[mid].d[1]; 38 if(l<mid) t[mid].ch[0]=build(l,mid-1,x^1); 39 if(mid<r) t[mid].ch[1]=build(mid+1,r,x^1); 40 update(mid); 41 return mid; 42 } 43 int dist(node t1,node t2){ 44 return abs(t1.d[0]-t2.d[0])+abs(t1.d[1]-t2.d[1]); 45 } 46 int calcmin(node x){ 47 int ret=0; 48 ret+=max(x.mx[0]-T.d[0],0); 49 ret+=max(T.d[0]-x.mx[1],0); 50 ret+=max(x.my[0]-T.d[1],0); 51 ret+=max(T.d[1]-x.my[1],0); 52 return ret; 53 } 54 int calcmax(node x){ 55 int d1=abs(T.d[0]-x.mx[0])+abs(T.d[1]-x.my[0]); 56 int d2=abs(T.d[0]-x.mx[0])+abs(T.d[1]-x.my[1]); 57 int d3=abs(T.d[0]-x.mx[1])+abs(T.d[1]-x.my[0]); 58 int d4=abs(T.d[0]-x.mx[1])+abs(T.d[1]-x.my[1]); 59 return max(max(d1,d2),max(d3,d4)); 60 } 61 void getmax(int k){ 62 ans=max(ans,dist(t[k],T)); 63 int l=t[k].ch[0]; 64 int r=t[k].ch[1]; 65 int dl=-inf,dr=-inf; 66 if(l) dl=calcmax(t[l]); 67 if(r) dr=calcmax(t[r]); 68 69 if(dl>dr){ 70 if(dl>ans) getmax(l); 71 if(dr>ans) getmax(r); 72 }else { 73 if(dr>ans) getmax(r); 74 if(dl>ans) getmax(l); 75 } 76 } 77 78 void getmin(int k){ 79 if(dist(t[k],T)) ans=min(ans,dist(t[k],T)); 80 int l=t[k].ch[0]; 81 int r=t[k].ch[1]; 82 int dl=inf,dr=inf; 83 if(l) dl=calcmin(t[l]); 84 if(r) dr=calcmin(t[r]); 85 if(dl<dr){ 86 if(dl<ans) getmin(l); 87 if(dr<ans) getmin(r); 88 }else { 89 if(dr<ans) getmin(r); 90 if(dl<ans) getmin(l); 91 } 92 } 93 94 int query(int f,int x,int y){ 95 T.d[0]=x;T.d[1]=y; 96 if(f==0) ans=inf, getmin(root); 97 else ans=-inf,getmax(root); 98 return ans; 99 } 100 }kd; 101 int main(){ 102 scanf("%d",&n); 103 for(int i=1;i<=n;i++){ 104 scanf("%d%d",&x[i],&y[i]); 105 p[i].d[0]=x[i]; 106 p[i].d[1]=y[i]; 107 } 108 root=kd.build(1,n,0); 109 int ans=inf; 110 for(int i=1;i<=n;i++){ 111 int v1=kd.query(0,x[i],y[i]); 112 int v2=kd.query(1,x[i],y[i]); 113 ans=min(ans,v2-v1); 114 } 115 printf("%d\n",ans); 116 return 0; 117 }