1. 程式人生 > 實用技巧 >松鼠的聚會

松鼠的聚會

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');}