BZOJ 3170 [Tjoi 2013]松鼠聚会 切比雪夫距离-->曼哈顿距离

Description

有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1。现在N个松鼠要走到一个松鼠家去,求走过的最短距离。

Input

第一行给出数字N,表示有多少只小松鼠。0<=N<=10^5
下面N行,每行给出x,y表示其家的坐标。
-10^9<=x,y<=10^9

Output

表示为了聚会走的路程和最小为多少。

Sample Input

6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2

Sample Output

20

HINT











……好菜啊才会切比雪夫距离……
根据题意可以斜走,那么(x1,y1)(x2,y2)之间的距离就是max(|x1-x2|,|y1-y2|)
然后……我就不会了= =

百度了一下发现这个东西叫做切比雪夫距离……
然后它可以转化成曼哈顿距离去的。
具体过程差不多就是拆成4个,取max这样子
反正推出来是(x,y)变成((x-y)/2,(x+y)/2)
然后距离就变成了两点之间的曼哈顿距离。
如何统计其它点到这个点的曼哈顿距离……
只要统计比x小的和与个数、比x大的和与个数就可以算出x到其它所有点的距离之和,
y同理,,不难理解吧……
就是说x和y是独立的……然后分开来求就通过去掉绝对值来搞。。

那么这个乱搞就好了……
树状数组什么的还要离散化,直接排序+二分水水掉……



#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int
    N=100005;
int n;
ll Y[N],sumx[N],sumy[N];
struct node{ll l,r;}X[N];
bool cmp(node p,node q){return p.l<q.l;}
void Pre(){
    int t1,t2;
    for (int i=1;i<=n;i++){
        scanf("%d%d",&t1,&t2);
        X[i].l=t1-t2,X[i].r=t1+t2;
        Y[i]=X[i].r;
    }
    sort(X+1,X+1+n,cmp),sort(Y+1,Y+1+n);
    sumx[0]=0LL,sumy[0]=0LL;
    for (int i=1;i<=n;i++) sumx[i]=sumx[i-1]+X[i].l;
    for (int i=1;i<=n;i++) sumy[i]=sumy[i-1]+Y[i];
}
ll solve(){
    ll ans=1e18;
    for (int i=1;i<=n;i++){
        ll t=X[i].l*(i-1)-sumx[i-1]+sumx[n]-sumx[i]-X[i].l*(n-i);
        int j=lower_bound(Y+1,Y+1+n,X[i].r)-Y;
        t+=X[i].r*(j-1)-sumy[j-1]+sumy[n]-sumy[j]-X[i].r*(n-j);
        ans=min(ans,t);
    }
    return ans>>1LL;
}
int main(){
    scanf("%d",&n);
    Pre();
    printf("%lld\n",solve());
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值