曼哈顿距离,欧几里得距离学习笔记
1. 定义:
二维下点坐标 ( x , y )
空间里有两个点( xi , yi ) ( xj , yj )
他们横坐标距离为 dx = | xi - xj | ,纵坐标距离为 dy = | yi - yj |
他们的切比雪夫距离是横坐标距离和纵坐标距离中值大的那一个 : max(dx,dy)
曼哈顿距离是横坐标距离与纵坐标距离的和 : dx+dy
2. 互相转换:
曼哈顿->切比雪夫:( x , y ) -> ( (x+y/2) , (x-y/2) )
这里用换完后的坐标计算曼哈顿,算出来的是原坐标的切比雪夫距离,下面同理。
切比雪夫->曼哈顿: ( x , y ) -> ( x+y , x-y )
3. 注意的点:
两个点a,b。a到原点的曼哈顿距离为da,b到原点的曼哈顿距离为db,ab两点的曼哈顿距离为dab,dab,da,db关系不大。切比雪夫同理。
4. 曼哈顿距离最小生成树:
5. 题目:
bzoj3170: [Tjoi2013]松鼠聚会
题意:平面上n个点,求所有的点到其中某一个点的切比雪夫距离的最小值。0<=N<=10^5
做法:切比雪夫->曼哈顿,变成了求所有的点到其中某一个点的曼哈顿距离的最小值。
预处理,使得能在o(1)算出某个点到所有点的曼哈顿距离,1~n扫每个点,更新答案即可。
怎么预处理?
单独考虑x轴时,点k到所有点的距离(x轴上)为(xk-x1)+...+(xk-x(k-1))+(x(k+1)-xk)+...+(xn-xk);
整理一哈~变成了((k-1)-(n-k) )*xk-(x1+...+x(k-1))+(x(k+1)+...+xn)
然后(x1+...+x(k-1))就是可爱的前缀和,(x(k+1)+...+xn)就是萌萌哒后缀和拉~
y轴同理~
坑点:在数据有点大,注意要先减后加,不然爆long long ,然后Inf要开到1e20
代码:
1 #include <bits/stdc++.h> 2 #define nmax 100005 3 #define inf 1e20 4 5 using namespace std; 6 typedef long long ll; 7 ll qzx[nmax]={0},qzy[nmax]={0},ix[nmax],iy[nmax]; 8 struct px{ 9 ll num,id; 10 bool operator < (const px & a) const { return num<a.num; } 11 }; 12 px x[nmax],y[nmax]; 13 14 int main(){ 15 //freopen("owo.in","r",stdin); 16 ll n,inx,iny,totx=0,toty=0; 17 scanf("%lld",&n); 18 for (int i=1; i<=n; i++) { 19 scanf("%lld%lld",&inx,&iny); 20 x[i].num=(inx+iny); //先不除以2,后面再解决 21 y[i].num=(inx-iny); 22 totx+=x[i].num; 23 toty+=y[i].num; 24 x[i].id=y[i].id=i; 25 } 26 sort(x+1,x+n+1); 27 sort(y+1,y+n+1); 28 for (int i=1; i<=n; i++) { 29 qzx[i]=qzx[i-1]+x[i].num; 30 qzy[i]=qzy[i-1]+y[i].num; 31 ix[x[i].id]=i; 32 iy[y[i].id]=i; 33 } 34 ll ans=inf; 35 for (int i=1; i<=n; i++) { 36 ll tx=0,ty=0,txi=ix[i],tyi=iy[i]; 37 tx-=qzx[txi-1]; 38 tx+=(totx-qzx[txi]); 39 tx+=(x[txi].num*(txi-1-n+txi)); 40 ty-=qzy[tyi-1]; 41 ty+=(toty-qzy[tyi]); 42 ty+=(y[tyi].num*(tyi-1-n+tyi)); 43 ans=min(ans,tx+ty); 44 } 45 cout<<ans/2<<endl; 46 return 0; 47 }