松鼠的聚会
description
有若干只松鼠住在可视为笛卡尔坐标系的草原上,它们想选定其中一只的家作为目的地去参加聚会,并且不希望走太长距离,请你求出最小距离.值得注意的是,一个点到其周围八个点距离均为$ 1 $.
solution
此题我们不难发现,任意两点间的距离为两点间横纵坐标差的绝对值的较大值,我们一般将这种距离叫做切比雪夫距离.其实,笛卡尔坐标系上两点\(P_{1}(x_{1},y_{1}),P_{2}(x_{2},y_{2})\),一共有三种距离,下面一一介绍.
第一种是我们最熟悉的笛卡尔距离,其表达式为\(|P_{1}P_{2}|=\sqrt{(x_{1}-x_{2})^{2}+(y_{1}-y_{2})^{2}}\)
第二种叫做曼哈顿距离,其表达式为\(|P_{1}P_{2}|=|x_{1}-x_{2}|+|y_{1}-y_{2}|\)
第三种比较少见,叫做切比雪夫距离,即本题要用到的.表达式如下:\(|P_{1}P_{2}|=max(|x_{1}-x_{2}|,|y_{1}-y_{2}|)\)
特别的是,曼哈顿距离和切比雪夫距离可以互相转换.我们考虑最简单的情况,在一个二维坐标系中,设原点为(0,0)(0,0),如果用曼哈顿距离表示,则与原点距离为11的点会构成一个边长为11的正方形.
如果用切比雪夫距离表示,则与原点距离为11的点会构成一个边长为22的正方形
第二个图像是由第一个图像放大两倍后旋转45°得到的.根据一堆神奇的性质我们可以\(YY\)出来,将图一中的点\((x,y)\)对应图二中的点\((\frac{x+y}{2},\frac{x-y}{2})\),那么就可进行互化了.
于是乎我们可以将本题转化为曼哈顿距离,即求\(Max_{i=1}^{n} \{ \sum_{j\not= i}|x_{i}-x_{j}| +\sum_{j\not= i}|y_{i}-y_{j}| \}\),去括号后利用前缀和维护,二分查找答案即可实现\(\Omicron(\log n)\)一次查询.
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define next MabLcdG
#define mod 1
#define debug puts("mlg")
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writesp(ll x);
inline void writeln(ll x);
const ll maxn=310000;
ll n;
struct node{
ll x,y;
}v[maxn];
ll sx[maxn],sy[maxn],lshx[maxn],lshy[maxn];
ll ans;
int main(){
n=read();
for(R ll i=1,x,y;i<=n;i++) x=read(),y=read(),v[i].x=lshx[i]=x+y,v[i].y=lshy[i]=x-y;
sort(lshx+1,lshx+n+1);
sort(lshy+1,lshy+n+1);
for(R ll i=1;i<=n;i++) sx[i]=sx[i-1]+lshx[i],sy[i]=sy[i-1]+lshy[i];
ans=((ull)1<<63)-1;
for(R ll i=1;i<=n;i++){
ll x=v[i].x,y=v[i].y;
ll res=0;
ll pos=lower_bound(lshx+1,lshx+n+1,x)-lshx;
res+=pos*x-(n-pos)*x-sx[pos]+sx[n]-sx[pos];
pos=lower_bound(lshy+1,lshy+n+1,y)-lshy;
res+=pos*y-(n-pos)*y-sy[pos]+sy[n]-sy[pos];
ans=min(ans,res);
}
writeln(ans>>1);
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}