bzoj 1941 kd-tree求最大最小曼哈顿距离

70 篇文章 0 订阅
27 篇文章 0 订阅

给出平面上n个点,求距离每个点最大距离减最小距离(不算自己)的最小值;(曼哈顿距离)

n<=500000;

#include <iostream>  
#include <algorithm>  
#include <cstring>  
#include <cstdio>  
#include <cmath>  
using namespace std;  
#define ll long long  
#define maxn 600000  
#define inf 2100000000  
int read()  
{  
    int x=0,f=1;char ch=getchar();  
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  
    return x*f;  
}  
int x[maxn],y[maxn];  
int D,n,m,rt;  
struct node  
{  
    int d[2],mx[2],mn[2],l,r;  
    friend bool operator < (node aa,node bb)  
    {  
        return aa.d[D]<bb.d[D];  
    }  
}p[maxn];  
int dis(node a,node b)  
{  
        return abs(a.d[1]-b.d[1])+abs(a.d[0]-b.d[0]);  
}  
struct tree  
{  
    node t[maxn],T;  
    int ans;  
    void update(int k){  
        int l=t[k].l,r=t[k].r;  
        for(int i=0;i<2;i++)  
        {  
            t[k].mn[i]=t[k].mx[i]=t[k].d[i];  
            if(l)t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]);  
            if(r)t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]);  
            if(l)t[k].mx[i]=max(t[k].mx[i],t[l].mx[i]);  
            if(r)t[k].mx[i]=max(t[k].mx[i],t[r].mx[i]);  
        }  
    }  
    int build(int l,int r,int now){  
        D=now;  
        int mid=(l+r)>>1;  
        nth_element(p+l,p+mid,p+r+1);  
        t[mid]=p[mid];  
        for(int i=0;i<2;i++)  
            t[mid].mn[i]=t[mid].mx[i]=t[mid].d[i];  
        if(l<mid)t[mid].l=build(l,mid-1,now^1);  
        if(r>mid)t[mid].r=build(mid+1,r,now^1);  
        update(mid);  
        return mid;  
    }  
    int getmn(node a){  
        int ans=0;  
        for(int i=0;i<2;i++)  
        {  
            ans+=max(T.d[i]-a.mx[i],0);  
            ans+=max(a.mn[i]-T.d[i],0);  
        }  
        return ans;  
    }  
    int getmx(node a){  
        int ans=0;  
        for(int i=0;i<2;i++)  
            ans+=max(abs(T.d[i]-a.mx[i]),abs(T.d[i]-a.mn[i]));  
        return ans;  
    }  
   
    void querymx(int x)  
    {  
        int l=t[x].l;  
        int r=t[x].r;  
        int tmp=dis(t[x],T);  
        ans=max(ans,tmp);  
        int ansl=-inf,ansr=-inf;  
        if(l) ansl=getmx(t[l]);  
        if(r) ansr=getmx(t[r]);  
        if(ansl>ansr)  
        {  
            if(ansl>ans) querymx(l);  
            if(ansr>ans) querymx(r);  
        }  
        else  
        {  
            if(ansr>ans) querymx(r);  
            if(ansl>ans) querymx(l);  
        }  
    }  
    void querymn(int x)  
    {  
        int l=t[x].l;  
        int r=t[x].r;  
        int tmp=dis(t[x],T);  
        if(tmp) ans=min(ans,tmp);  
        int ansl=inf,ansr=inf;  
        if(l) ansl=getmn(t[l]);  
        if(r) ansr=getmn(t[r]);  
        if(ansl<ansr)  
        {  
            if(ansl<ans) querymn(l);  
            if(ansr<ans) querymn(r);  
        }  
        else  
        {  
            if(ansr<ans) querymn(r);  
            if(ansl<ans) querymn(l);  
        }  
    }  
    int query(int f,int x,int y)  
    {  
        T.d[0]=x;T.d[1]=y;  
        if(f==0)ans=inf,querymn(rt);  
        else ans=-inf,querymx(rt);  
        return ans;  
    }  
}kd;  
   
int main()  
{  
    n=read();  
    for(int i=1;i<=n;i++)  
    {  
        x[i]=read(),y[i]=read();  
        p[i].d[0]=x[i];p[i].d[1]=y[i];  
    }  
    rt=kd.build(1,n,0);  
    int ans=inf;  
    for(int i=1;i<=n;i++)  
    {  
        int mn=kd.query(0,x[i],y[i]);  
        int mx=kd.query(1,x[i],y[i]);  
        ans=min(ans,mx-mn);  
    }  
    printf("%d\n",ans);  
    return 0;  
}  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值