HDU - 5992 ——Finding Hotels (KD树求最近点)

题目链接:https://vjudge.net/contest/332630#problem/K

/*
HDU - 5992 KD树求最近点
t组数据,n个酒店,m个客人
后接n行,给出酒店坐标x,y,酒店价格w
m行,给出客人坐标x,y。客人最大能接受价格w
求客人最大能接受价格内的最近酒店是哪个,距离相同时输出,选择顺序靠前的酒店
输出m行,第i个客人选择的酒店坐标,价格
1
3 3
1 1 1
3 2 3
2 3 2
2 2 1
2 2 2
2 2 3
ans:
1 1 1
2 3 2
3 2 3

把酒店价格当成第三个维度,建立三维KD树,搜索满足条件下的最近点
*/
#include<bits/stdc++.h>
#define M 200010
#define ll long long
using namespace std;
ll t,n,m,wb,x,y,z,rt,dis,ans;
ll sta[M],tot;
const ll inf=1e18;
struct point
{
    ll c[3],w,id;
    bool operator <  (const point a) const
    {
        return this->c[wb]<a.c[wb];
    }
} P[M];
struct node
{
    ll mi[3],mx[3],ls,rs;
    point tp;
} T[M];
void up(ll r)
{
    ll ls=T[r].ls,rs=T[r].rs;
    for(ll i=0; i<3; i++)
    {
        T[r].mi[i]=T[r].mx[i]=T[r].tp.c[i];
        if(ls)
        {
            T[r].mi[i]=min(T[r].mi[i],T[ls].mi[i]);
            T[r].mx[i]=max(T[r].mx[i],T[ls].mx[i]);
        }
        if(rs)
        {
            T[r].mi[i]=min(T[r].mi[i],T[rs].mi[i]);
            T[r].mx[i]=max(T[r].mx[i],T[rs].mx[i]);
        }
    }
}
ll build(ll l,ll r,ll k)//暴力建树
{
    if(l>r) return 0;
    ll mid=(l+r)>>1,now=++tot;
    wb=k,nth_element(P+l,P+mid,P+r+1),T[now].tp=P[mid];
    T[now].ls=build(l,mid-1,(k+1)%3),T[now].rs=build(mid+1,r,(k+1)%3);
    up(now);
    return now;
}
ll getdis(ll rt)//返回点集中可能的最近点距离
{
    ll res=0;
    if(z<T[rt].mi[2]) return inf+1;
    if(x>T[rt].mx[0]) res+=(x-T[rt].mx[0])*(x-T[rt].mx[0]);
    if(x<T[rt].mi[0]) res+=(T[rt].mi[0]-x)*(T[rt].mi[0]-x);
    if(y>T[rt].mx[1]) res+=(y-T[rt].mx[1])*(y-T[rt].mx[1]);
    if(y<T[rt].mi[1]) res+=(T[rt].mi[1]-y)*(T[rt].mi[1]-y);
    return res;
}
void query(ll rt)
{
    ll dm=0,dl=inf+1,dr=inf+1,ls=T[rt].ls,rs=T[rt].rs;
    if(T[rt].tp.c[2]>z) dm=inf;
    if(dm==0)
    {
        dm = (T[rt].tp.c[0]-x)*(T[rt].tp.c[0]-x)+(T[rt].tp.c[1]-y)*(T[rt].tp.c[1]-y);
        if(dm<dis)
        {
            dis=dm;
            ans=rt;
        }
        else if(dm==dis)
        {
            ans = T[ans].tp.id < T[rt].tp.id ? ans:rt;
        }
    }
    if(ls) dl=getdis(ls);
    if(rs) dr=getdis(rs);
    if(dl<dr)
    {
        if(dl<=dis) query(ls);
        if(dr<=dis) query(rs);
    }
    else
    {
        if(dr<=dis) query(rs);
        if(dl<=dis) query(ls);
    }
}
int main()
{
    for(scanf("%lld",&t); t; t--)
    {
        tot=0;
        scanf("%lld%lld",&n,&m);
        for(ll i=1; i<=n; i++)
        {
            for(ll j=0; j<3; j++) scanf("%lld",&P[i].c[j]);
            P[i].id=i;
        }
        rt=build(1,n,0);
        for(ll i=1; i<=m; i++)
        {
            scanf("%lld%lld%lld",&x,&y,&z);
            dis=inf;
            query(rt);
            printf("%lld %lld %lld\n",T[ans].tp.c[0],T[ans].tp.c[1],T[ans].tp.c[2]);
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值