#距离#JZOJ 3256 BZOJ 3170 洛谷 3964 松鼠聚会

本文详细解析了一种将切比雪夫距离转换为曼哈顿距离的算法,通过坐标变换和前缀和优化,有效地解决了在特定场景下计算两点间距离的问题。文章提供了完整的代码实现,包括坐标变换、排序、前缀和计算等关键步骤。

题目


分析

首先这个距离是切比雪夫距离,得把它转换成曼哈顿距离,也就是把 ( x , y ) (x,y) (x,y)变成 ( x + y 2 , x − y 2 ) (\frac{x+y}{2},\frac{x-y}{2}) (2x+y,2xy)
为了避免精度,那么选择把坐标扩大一倍,最后答案除以2
然后横坐标和纵坐标显然可以分别处理,那么对于排序后第 i i i个坐标
那么 ∣ y 1 − y i ∣ + ∣ y 2 − y i ∣ + ∣ y n − 1 − y i ∣ + ∣ y n − y i ∣ |y_1-y_i|+|y_2-y_i|+|y_{n-1}-y_i|+|y_n-y_i| y1yi+y2yi+yn1yi+ynyi
i y i − ∑ j = 1 i y j + ∑ j = i + 1 n y j − ( n − i ) y i iy_i-\sum_{j=1}^iy_j+\sum_{j=i+1}^{n}y_j-(n-i)y_i iyij=1iyj+j=i+1nyj(ni)yi
可以用前缀和优化,所以式子可以化为
( i + i − n ) y i + s n − s i − s i (i+i-n)y_i+s_n-s_i-s_i (i+in)yi+snsisi


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; int x[N],tx[N],n,y[N],ty[N];
typedef unsigned long long ull; ull sx[N],sy[N];
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
signed main(){
	n=iut(); rr ull ans=1ll<<63; 
	for (rr int i=1;i<=n;++i){
		rr int xx=iut(),yy=iut();
		x[i]=tx[i]=xx+yy,y[i]=ty[i]=xx-yy;
	}
	sort(tx+1,tx+1+n),sort(ty+1,ty+1+n);
	for (rr int i=1;i<=n;++i) sx[i]=sx[i-1]+tx[i];
	for (rr int i=1;i<=n;++i) sy[i]=sy[i-1]+ty[i];
	for (rr int i=1;i<=n;++i){
		rr int px=lower_bound(tx+1,tx+1+n,x[i])-tx; rr ull sum=0;
		sum+=1ll*((px<<1)-n)*x[i]+sx[n]-(sx[px]<<1);
		rr int py=lower_bound(ty+1,ty+1+n,y[i])-ty;
		sum+=1ll*((py<<1)-n)*y[i]+sy[n]-(sy[py]<<1);
		ans=ans<sum?ans:sum;
	}
	return !printf("%llu",ans>>1);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值