定义
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;
}