bzoj3170 [Tjoi2013]松鼠聚会 切比雪夫距离

http://www.elijahqi.win/archives/3126
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

Source

考虑松鼠行进的路线就是切比雪夫距离 但是切比雪夫距离无法快速计算 所以考虑转化坐标系 将切比雪夫距离等价于曼哈顿距离 就可以预处理前缀和后缀和每次o1分开计算答案即可

所以将原坐标转化为((x1+x2)/2,(x1-x2)/2)即可算曼哈顿距离 他们是等价的

证明的大致思路是 将曼哈顿距离写成绝对值形式 然后再将绝对值的两种情况写成取max形式 最后在化简讨论换元即可

#include<cstdio>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e5+10;
struct node{int x,y;}p[N];
inline bool cmp1(const int &a,const int &b){return p[a].x<p[b].x;}
inline bool cmp2(const int &a,const int &b){return p[a].y<p[b].y;}
int n,rk1[N],rk2[N],bl1[N],bl2[N]; 
ll pre[N],pre1[N],suc[N],suc1[N];
int main(){
    freopen("bzoj3170.in","r",stdin);
    n=read();int x,y;
    for (int i=1;i<=n;++i) {
        x=read();y=read();p[i].x=x+y;p[i].y=x-y;
    }ll ans=1LL<<60;
    for (int i=1;i<=n;++i) bl1[i]=bl2[i]=i;
    sort(bl1+1,bl1+1+n,cmp1);sort(bl2+1,bl2+1+n,cmp2);
    for (int i=1;i<=n;++i) pre[i]=pre[i-1]+p[bl1[i]].x;
    for (int i=n;i;--i) suc[i]=suc[i+1]+p[bl1[i]].x;
    for (int i=1;i<=n;++i) pre1[i]=pre1[i-1]+p[bl2[i]].y;
    for (int i=n;i;--i) suc1[i]=suc1[i+1]+p[bl2[i]].y;
    for (int i=1;i<=n;++i) rk1[bl1[i]]=i,rk2[bl2[i]]=i;
    for (int i=1;i<=n;++i){
        static int id;static ll tmpx,tmpy;
        id=rk1[i];tmpx=(ll)id*p[i].x-pre[id]+suc[id+1]-(ll)p[i].x*(n-id);
        id=rk2[i];tmpy=(ll)id*p[i].y-pre1[id]+suc1[id+1]-(ll)p[i].y*(n-id);
        ans=min(ans,tmpx+tmpy);
    }printf("%lld\n",ans>>1);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值