【K-D树 求最近最远距离】BZOJ 1941 [Sdoi2010]Hide and Seek

Problem Description

给你n个点(二维),让你求所有点 到最远点 和最近点 的距离差最小

思路:

自身点不算。
求个距离该点,最近距离。和 距离该点,最远距离即可。
这里的距离指的是 曼哈顿距离

#include<bits/stdc++.h>
using namespace std;
const int MAX = 500010;
const int inf = 0x3f3f3f3f;
const int DIM = 2;
struct node
{
    int l, r;
    int d[DIM], maxn[DIM], minn[DIM];
    inline void maintain()//初始化
    {
        l = r = 0;
        for(int i = 0; i < DIM; i++)
            maxn[i] = minn[i] = d[i];
    }
}tree[MAX];
int D;
bool operator < (const node &a, const node &b)//重载,从小到大
{
    return a.d[D] < b.d[D];
}
inline void Merge(int mid)//归并,向上更新
{
    int son[2] = {tree[mid].l, tree[mid].r};
    for(int i = 0; i < 2; i++)
    {
        if(!son[i]) continue;
        for(int j = 0; j < DIM; j++)
        {
            tree[mid].maxn[j] = max(tree[mid].maxn[j], tree[son[i]].maxn[j]);
            tree[mid].minn[j] = min(tree[mid].minn[j], tree[son[i]].minn[j]);
        }
    }
}
int build(int l, int r, int now)//建树
{
    int mid = (l+r) >> 1;
    D = now;
    nth_element(tree+l, tree+mid, tree+r+1);//对于now维,以mid为中间,左边都是比它小,右边都是比它大。
    tree[mid].maintain();//初始化
    if(l < mid) tree[mid].l = build(l, mid-1, (now+1)%DIM);
    if(r > mid) tree[mid].r = build(mid+1, r, (now+1)%DIM);
    Merge(mid);
    return mid;
}
int ans1, ans2;
int partionMin(int o, int k)//求最小可能值
{
    int red = 0;
    for(int i = 0; i < DIM; i++)
    {
        if(tree[k].d[i] > tree[o].maxn[i]) red += tree[k].d[i] - tree[o].maxn[i];
        if(tree[k].d[i] < tree[o].minn[i]) red += tree[o].minn[i] - tree[k].d[i];
    }
    return red;
}
int partionMax(int o, int k)//求最大可能值
{
    int red = 0;
    for(int i = 0; i < DIM; i++)
    {
        red += max(abs(tree[k].d[i] - tree[o].maxn[i]), abs(tree[k].d[i] - tree[o].minn[i]));
    }
    return red;
}
void queryMin(int o, int k)//求最小距离
{
    int dm = abs(tree[k].d[0] - tree[o].d[0]) + abs(tree[k].d[1] - tree[o].d[1]);
    if(o == k) dm = inf;//自身点不算。
    if(ans1 > dm) ans1 = dm;
    int dl = tree[o].l ? partionMin(tree[o].l, k) : inf;
    int dr = tree[o].r ? partionMin(tree[o].r, k) : inf;
    if(dl < dr)
    {
        if(dl < ans1) queryMin(tree[o].l, k);
        if(dr < ans1) queryMin(tree[o].r, k);
    }
    else
    {
        if(dr < ans1) queryMin(tree[o].r, k);
        if(dl < ans1) queryMin(tree[o].l, k);
    }
}
void queryMax(int o, int k)//求最大距离
{
    int dm = abs(tree[k].d[0] - tree[o].d[0]) + abs(tree[k].d[1] - tree[o].d[1]);
    if(ans2 < dm) ans2 = dm;
    int dl = tree[o].l ? partionMax(tree[o].l, k) : 0;
    int dr = tree[o].r ? partionMax(tree[o].r, k) : 0;
    if(dl > dr)
    {
        if(dl > ans2) queryMax(tree[o].l, k);
        if(dr > ans2) queryMax(tree[o].r, k);
    }
    else
    {
        if(dr > ans2) queryMax(tree[o].r, k);
        if(dl > ans2) queryMax(tree[o].l, k);
    }
}
int main()
{
    int n, i, j;
    while(~scanf("%d", &n))
    {
        for(i = 1; i <= n; i++)
            for(j = 0; j < DIM; j++)
            scanf("%d", &tree[i].d[j]);
        int root = build(1, n, 0);
        int Ans;
        for(i = 1; i <= n; i++)
        {
            ans1 = inf;
            ans2 = 0;
            queryMin(root, i);
            queryMax(root, i);
            Ans = min(Ans, ans2 - ans1);
        }
        printf("%d\n", Ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值