【kd-tree】专题总结
感谢orz神·小黑的指导
kd-tree就是用来计算若干维空间k近/远点的数(shou)据(suo)结(you)构(hua)
建树
假设题目是k维的点
第deep层就是用deep%k+1维把所有点分为两块
取deep%k+1维中位数的点做为当前子树的根节点
再把该维比这个点小的点扔到左子树 比这个点大的扔到右子树 递归处理
详见代码
void Sort(ll l,ll r,ll k){ cmpp=k; sort(kd+l,kd+r+,cmp); }
ll build(ll l,ll r,ll deep){
if (l==r){
kd[l].lc=kd[r].rc=;
return l;
}
Sort(l,r,deep);
ll mid=(l+r)/;
if (l<mid) kd[mid].lc=build(l,mid-,deep%k+);
else kd[mid].lc=;
if (mid<r) kd[mid].rc=build(mid+,r,deep%k+);
else kd[mid].rc=;
return mid;
}
查询
询问离点S的前m近点 说它是搜索优化就是因为这里- -
维护大根堆记录答案 当元素个数小于m时直接push
反正判断有木有 比最大值小 有就pop再push
当搜索当t点是先用该点到S的距离维护堆
再判断如果S的deep%k+1维 比t点该维小就先搜索左子树 否则搜索右子树
搜索完一颗子树后 判断如果S到t点deep%k+1维的距离就≥ans显然继续搜索没用 就不继续搜索 否则搜索另一颗子树
代码
void push(ll t){
ll dis=getdis(S,poi[t]);
if (size==m){
if (dis>que.top().dis) return;
else{
que.pop();
que.push(info(dis,t));
}
}else{
++size;
que.push(info(dis,t));
}
}
void makeans(ll t,ll deep){
if (!t) return;
push(kd[t].t);
if (S.d[deep]<=kd[t].p.d[deep]){
makeans(kd[t].lc,deep%k+);
if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].rc,deep%k+);
}else{
makeans(kd[t].rc,deep%k+);
if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].lc,deep%k+);
}
}
最远点
这里讲的都是m近点- -
如果是m远点其实是差不多的 只是维护的东西不太一样
需要维护每维的min和max
询问的时候基本同理yy下即可
求k位距离S的m近点代码
#include <cstdio>
#include <algorithm>
#include <queue>
typedef long long ll;
using namespace std;
const ll N=;
struct inpo{
ll d[];
}poi[N],S,ans[];
struct inkd{
ll t,lc,rc;
inpo p;
inkd(const ll a=,const ll b=,const ll c=):
t(a),lc(b),rc(c){}
}kd[N];
struct info{
ll dis,t;
info(const ll a=,const ll b=):
dis(a),t(b){}
};
priority_queue <info> que;
ll root,n,k,m,t,cmpp,size;
inline bool operator <(info a,info b){ return a.dis<b.dis; }
inline bool cmp(inkd a,inkd b){ return a.p.d[cmpp]<b.p.d[cmpp]; }
void Sort(ll l,ll r,ll k){ cmpp=k; sort(kd+l,kd+r+,cmp); }
ll sqr(ll x){ return x*x; }
ll getdis(inpo a,inpo b){
ll res=;
for (ll i=;i<=k;i++) res+=sqr(a.d[i]-b.d[i]);
return res;
}
ll build(ll l,ll r,ll deep){
if (l==r){
kd[l].lc=kd[r].rc=;
return l;
}
Sort(l,r,deep);
ll mid=(l+r)/;
if (l<mid) kd[mid].lc=build(l,mid-,deep%k+);
else kd[mid].lc=;
if (mid<r) kd[mid].rc=build(mid+,r,deep%k+);
else kd[mid].rc=;
return mid;
}
void push(ll t){
ll dis=getdis(S,poi[t]);
if (size==m){
if (dis>que.top().dis) return;
else{
que.pop();
que.push(info(dis,t));
}
}else{
++size;
que.push(info(dis,t));
}
}
void makeans(ll t,ll deep){
if (!t) return;
push(kd[t].t);
if (S.d[deep]<=kd[t].p.d[deep]){
makeans(kd[t].lc,deep%k+);
if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].rc,deep%k+);
}else{
makeans(kd[t].rc,deep%k+);
if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].lc,deep%k+);
}
}
int main(){
freopen("hdu4347.in","r",stdin);
freopen("hdu4347.out","w",stdout);
while (~scanf("%I64d%I64d",&n,&k)){
for (ll i=;i<=n;i++){
for (ll j=;j<=k;j++) scanf("%I64d",&poi[i].d[j]);
kd[i].t=i,kd[i].p=poi[i];
}
root=build(,n,);
scanf("%I64d",&t);
for (;t;t--){
size=;
for (ll i=;i<=k;i++) scanf("%I64d",&S.d[i]);
scanf("%I64d",&m);
printf("the closest %I64d points are:\n",m);
makeans(root,);
for (ll i=;i<=m;i++){
ans[i]=poi[que.top().t];
que.pop();
}
for (ll i=m;i;i--){
for (ll j=;j<=k;j++){
printf("%I64d",ans[i].d[j]);
if (j<k) printf(" ");
}
puts("");
}
}
}
fclose(stdin);
fclose(stdout);
}
【kd-tree】专题总结的更多相关文章
- AOJ DSL_2_C Range Search (kD Tree)
Range Search (kD Tree) The range search problem consists of a set of attributed records S to determi ...
- k-d tree 学习笔记
以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...
- 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree
2648: SJY摆棋子 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2459 Solved: 834[Submit][Status][Discu ...
- K-D Tree
这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...
- K-D Tree题目泛做(CXJ第二轮)
题目1: BZOJ 2716 题目大意:给出N个二维平面上的点,M个操作,分为插入一个新点和询问到一个点最近点的Manhatan距离是多少. 算法讨论: K-D Tree 裸题,有插入操作. #inc ...
- k-d Tree in TripAdvisor
Today, TripAdvisor held a tech talk in Columbia University. The topic is about k-d Tree implemented ...
- k-d tree算法
k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构.主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索). 应用背景 SIFT算法中做特征点匹配的时候就会利用到k ...
- k-d tree模板练习
1. [BZOJ]1941: [Sdoi2010]Hide and Seek 题目大意:给出n个二维平面上的点,一个点的权值是它到其他点的最长距离减最短距离,距离为曼哈顿距离,求最小权值.(n< ...
- [模板] K-D Tree
K-D Tree K-D Tree可以看作二叉搜索树的高维推广, 它的第 \(k\) 层以所有点的第 \(k\) 维作为关键字对点做出划分. 为了保证划分均匀, 可以以第 \(k\) 维排名在中间的节 ...
- BZOJ3489 A simple rmq problem K-D Tree
传送门 什么可持久化树套树才不会写呢,K-D Tree大法吼啊 对于第\(i\)个数,设其前面最后的与它值相同的位置为\(pre_i\),其后面最前的与它值相同的位置为\(aft_i\),那么对于一个 ...
随机推荐
- 南阳理工ACM 括号匹配问题,并求出使得括号能够匹配需要新增的最小括号数(括号匹配(二))
描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起 ...
- CakeDC(cakephp company)Git workflow--适合于较大团队大型项目开发
CakeDC Git workflow是一个项目开发和版本发布的工作流,在这个工作流程中开发和版本发布周期是基于几个关键阶段(key phases): Development: 所有活跃的开发活动都由 ...
- JAVA字符串格式化-String.format()的使用 (转载)
常规类型的格式化 String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处.format()方法有两种重 ...
- HDU 1907 (博弈) John
参见上一篇博客,里面有分析和结论. #include <cstdio> int main() { int T; scanf("%d", &T); while(T ...
- HDU 5033 (单调栈维护凸包) Building
题意: 一个人在x轴上,他的左右两侧都有高楼,给出楼的横坐标Xi和高度Hi还有人的位置pos,求人所能看到的天空的最大角度. 分析: 将建筑物和人的位置从左到右排序,对于每个位置利用栈求一次人左边建筑 ...
- 51nod1442 士兵的旅行
裸网络流拆点就可以了... #include<cstdio> #include<cstring> #include<cctype> #include<algo ...
- acdream 1683 村民的怪癖(KMP,经典变形)
Problem Description 娜娜费劲九牛二虎之力终于把糖果吃完了(说好的吃不完呢?骗人,口亨~),于是,缘溪行,忘路之远近.忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,娜娜甚异之 ...
- Spark源码阅读(1): Stage划分
Spark中job由action动作生成,那么stage是如何划分的呢?一般的解答是根据宽窄依赖划分.那么我们深入源码看看吧 一个action 例如count,会在多次runJob中传递,最终会到一个 ...
- 【转】Cocos2d-x下Lua调用自定义C++类和函数的最佳实践
转自:http://segmentfault.com/blog/hongliang/1190000000631630 关于cocos2d-x下Lua调用C++的文档看了不少,但没有一篇真正把这事给讲明 ...
- ON、WHERE、HAVING的区别
ON .WHERE.HAVING都能通过限制条件筛选数据,但他们的使用及其不同.下面我们来分析三者之间的区别. 1. ON 和WHERE 所有的查询都回产生一个中间临时报表,查询结果就是从 ...