KDtree 知识点简记 + 例题(HDU 5992)

定义

int MAX_DIM; ///所讨论的空间的维度
struct node{
	int x[MAX_DIM];///所有维度的坐标信息
}KDtree[maxn];

操作

建树

按顺序选取维度

dim = (dim + 1) % MAX_DIM

按照目前的维度划分成两个空间

build(l, r, dim)
	……
	nth_element(KDtree + l, KDtree + mid, KDtree +  r + 1, [dim](const node& a, const node& b){return a.x[dim] < b.x[dim]});

查询

知识:对于KDtree中按照维度dim划分的那一层,可以知道每个点到该K-1维度的划分空间的距离就是dim方向上的距离

查询结点node,与mid(划分的K-1维度空间)结点的dim(a方向上的坐标)做比较,确定所属子空间。

int mini_dis///存储查询点到所有KDtree结点的最短的距离(存欧几里得距离或者欧几里得距离的平方)
int dist(node a, node b){///返回欧几里得距离或者欧几里得距离的平方
	return ……;
}

query(&node, l, r, dim)
	……
	if(node.x[dim] < KDtree[mid].x[dim]){
		query(node, l, mid - 1, (dim + 1) % MAX_DIM); ///结点在这一侧,查该子树
		///node已经更新为子树中的最优解,考虑是否与另一颗子树有交界,这时只需要看dim维度上的距离与mini_dis的大小关系
		if((KDtree[mid].x[dim] - node.x[dim]) * (KDtree[mid].x[dim] - node.x[dim]) < mini_dis){///与另一颗子树有相交,可能有更优解在另一颗子树上
			query(node, mid + 1, r, (dim + 1) % MAX_DIM);			
		}
	}else{
		query(node, mid + 1, r, (dim + 1) % MAX_DIM);
		if((KDtree[mid].x[dim] - node.x[dim]) * (KDtree[mid].x[dim] - node.x[dim]) < mini_dis){
			query(node, l, mid - 1, (dim + 1) % MAX_DIM);
		}
	}

例题

K - Finding Hotels HDU - 5992
HDU 5992

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct node{
    ll x[2], c;
    int id;
    node(ll xx = 0, ll yy = 0, ll cc = 0, int idd = 0) : x({xx, yy}), c(cc), id(idd){}
} hotel[maxn];
ll mini, cost;///最短距离 ///花费
int index; ///输入下标
int ans;///hotel下标
ll dist(node a, node b){
    return (a.x[0] - b.x[0]) * (a.x[0] - b.x[0]) + (a.x[1] - b.x[1]) * (a.x[1] - b.x[1]);
}
void build(int l, int r, int dim){
    if(l >= r) return ;
    int mid = l + r >> 1;
    nth_element(hotel + l, hotel + mid, hotel + r + 1, [dim](const node &a, const node &b){return a.x[dim] < b.x[dim];});
    build(l, mid - 1, dim ^ 1);
    build(mid + 1, r, dim ^ 1);
}
void query(const node &a, int l, int r, int dim){
    if(l > r) return ;
    int mid = l + r >> 1;
    ll dis = dist(a, hotel[mid]);
    if(a.c >= hotel[mid].c && (dis < mini || (dis == mini && hotel[mid].id < index))){
        mini = dis, index = hotel[mid].id, cost = hotel[mid].c, ans = mid;
    } n家旅店,每个旅店都有坐标x,y,每晚价钱z,m个客人,坐标x,y,钱c,问你每个客人最近且能住进去(非花最少钱)的旅店,一样近的选排名靠前的。
    if(a.x[dim] < hotel[mid].x[dim]){
        query(a, l, mid - 1, dim ^ 1);
        if(mini >= (hotel[mid].x[dim] - a.x[dim]) * (hotel[mid].x[dim] - a.x[dim])){
            query(a, mid + 1, r, dim ^ 1);
        }
    }else{
        query(a, mid + 1, r, dim ^ 1);
        if(mini >= (hotel[mid].x[dim] - a.x[dim]) * (hotel[mid].x[dim] - a.x[dim])){
            query(a, l, mid - 1, dim ^ 1);
        }
    }
}
int main(){
    int T; scanf("%d", &T);
    while(T--){
        int n, m; scanf("%d %d", &n, &m);
        for(int i = 0; i < n; i++){
            ll x, y, c; scanf("%lld %lld %lld", &hotel[i].x[0], &hotel[i].x[1], &hotel[i].c);
            hotel[i].id = i;
        }
        build(0, n - 1, 0);
        while(m--){
            struct node tem;
            scanf("%lld %lld %lld", &tem.x[0], &tem.x[1], &tem.c);
            mini = INF;
            query(tem, 0, n - 1, 0);
            printf("%lld %lld %lld\n", hotel[ans].x[0], hotel[ans].x[1], hotel[ans].c);
        }
    }
    return 0;
}

参考来源

博客 题目题解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值