HDU - 5992 K - Finding Hotels kd-tree求最近点对 改板子

题意:

给定n个旅馆,m个人,每个旅馆有一个价格,每个人有个能承受的最大的价格

对于每个人,输出离他最近的,并且价格在其承受范围之内的旅馆的坐标和价格

思路:

这个题一看就是最近点对,但是也没想那么多,直接套上kd-tree板子改了一下就过了

其实这个题要是所有的旅馆在一个大圆上,所有的人都在圆心附近,这样的话复杂度就很高了,可能是随机的数据比较弱

再说kd-tree: 刚刚现学的,现手推了一下板子,就是按坐标的维度建一棵二叉树,查找的时候按照远近的规则往下查找,复杂度logn;

处理这个题的时候,n个旅馆直接建树,对于m个人来说,每次查询的时候,先插入进去,删点标记flg设为1;直接查找,在更新最优解(最短距离)时,加上一个条件,就是旅馆价格在这个人承受范围内的话才进行判定更新,然后依次查询;

 

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5;
const ll INF = 0x3f3f3f3f3f3f3f3f;

struct kdnode {
    ll l,r,x[2], v;
    bool flg;
} kdt[N],pt;
int cnt,D,rt;
int n,m;
void init() {
    D = 2;
    cnt = 0;
    rt = -1;
}

int add(kdnode pt) {
    kdt[cnt].flg = 0;
    kdt[cnt].l = kdt[cnt].r = -1;
    kdt[cnt].v = pt.v;
    for(int i = 0; i < D; i++)
        kdt[cnt].x[i] = pt.x[i];
    return cnt++;
}

void insert_(int rt,kdnode pt,int d) {
    d %= D;
    if(pt.x[d]<kdt[rt].x[d]) {
        if(kdt[rt].l==-1)
            kdt[rt].l = add(pt);
        else
            insert_(kdt[rt].l,pt,d+1);
    } else {
        if(kdt[rt].r==-1)
            kdt[rt].r = add(pt);
        else
            insert_(kdt[rt].r,pt,d+1);
    }
}

ll dist(kdnode a,kdnode b) {
    ll ret = 0;
    for(int i = 0; i < D; i++)
        ret += (a.x[i]-b.x[i])*(a.x[i]-b.x[i]);
    return ret;
}

int idx;
ll ds;
void query(int rt,kdnode pt,int d) {
    d %= D;
    if(rt==-1)
        return;
    if(!kdt[rt].flg && kdt[rt].v <= pt.v) {
        ll dss = dist(kdt[rt],pt);
        if(ds>dss)
            idx=rt,ds=dss;
    }
    if(pt.x[d]<=kdt[rt].x[d]) {
        query(kdt[rt].l,pt,d+1);
        ll dd = (kdt[rt].x[d]-pt.x[d])*(kdt[rt].x[d]-pt.x[d]);
        if(dd<ds)
            query(kdt[rt].r,pt,d+1);
    }
    if(pt.x[d]>=kdt[rt].x[d]) {
        query(kdt[rt].r,pt,d+1);
        ll dd = (kdt[rt].x[d]-pt.x[d])*(kdt[rt].x[d]-pt.x[d]);
        if(dd<ds)
            query(kdt[rt].l,pt,d+1);
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) {
            scanf("%lld%lld", &pt.x[0], &pt.x[1]);
            scanf("%lld", &pt.v);
            if(rt == -1) {
                rt = add(pt);
            } else {
                insert_(rt, pt, 0);
            }
        }
        for(int i = 1; i <= m; ++i) {
            idx = rt;
            ds = INF;
            scanf("%lld%lld", &pt.x[0], &pt.x[1]);
            scanf("%lld", &pt.v);
            if(rt == -1) {
                rt = add(pt);
            } else {
                insert_(rt, pt, 0);
            }
            kdt[n+i-1].flg = 1;
            query(rt, kdt[n+i-1], 0);
            printf("%lld %lld %lld\n", kdt[idx].x[0], kdt[idx].x[1], kdt[idx].v);
        }
    }

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值