BZOJ3170:[TJOI2013]松鼠聚会

题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=3170

通过分析可以发现,题目所说的两点之间的距离就是切比雪夫距离。

两点之间欧几里得距离:\(\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}\)

两点之间曼哈顿距离:\(|x_1-x_2|+|y_1+y_2|\)

两点之间切比雪夫距离:\(max(|x1-x2|,|y1-y2|)\)

曼哈顿距离转切比雪夫距离:\((x,y)--->(x+y,x-y)\)

切比雪夫距离转曼哈顿距离:\((x,y)--->(\frac{x+y}{2},\frac{x-y}{2})\)

由于一个点到多个点的曼哈顿距离可以通过前缀和后缀和\(O(1)\)求,而切比雪夫只能\(O(n)\)求,所以我们这题只需要把坐标转化一下求曼哈顿距离即可。为了避免\(double\),转坐标的时候不除二,最后答案再除二。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn=1e5+5;

int n;ll res=1e18;
ll sum_pre[maxn],sum_suf[maxn],ans[maxn];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct point {
    int x,y,id;
}p[maxn];

bool cmp_x(point a,point b) {return a.x<b.x;}

bool cmp_y(point a,point b) {return a.y<b.y;}

int main() {
    n=read();
    for(int i=1;i<=n;i++) {
        int x=read(),y=read();
        p[i].x=x+y,p[i].y=x-y;
        p[i].id=i;
    }
    sort(p+1,p+n+1,cmp_x);
    for(int i=n;i;i--)
        sum_suf[i]=sum_suf[i+1]+p[i].x;
    for(int i=1;i<=n;i++) {
        sum_pre[i]=sum_pre[i-1]+p[i].x;
        if(i!=1)ans[p[i].id]=1ll*p[i].x*(i-1)-sum_pre[i-1];
        if(i!=n)ans[p[i].id]+=sum_suf[i+1]-1ll*p[i].x*(n-i);
    }
    sort(p+1,p+n+1,cmp_y);
    for(int i=n;i;i--)
        sum_suf[i]=sum_suf[i+1]+p[i].y;
    for(int i=1;i<=n;i++) {
        sum_pre[i]=sum_pre[i-1]+p[i].y;
        if(i!=1)ans[p[i].id]+=1ll*p[i].y*(i-1)-sum_pre[i-1];
        if(i!=n)ans[p[i].id]+=sum_suf[i+1]-1ll*p[i].y*(n-i);
        res=min(res,ans[p[i].id]>>1);
    }
    printf("%lld\n",res);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKMer/p/10387063.html