【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\),那么对于一个 ...
随机推荐
- Linux常用到的指令汇总
Linux常用到的指令汇总 根据鸟哥linux私房菜上定义的:一定要先學會的指令:ls, more, cd, pwd, rpm, ifconfig, find 登入與登出(開機與關機):telnet, ...
- 不同tomcat配置不同的jdk
修改Tomcat两个配置文件,tomcat/bin/catalina.sh . tomcat/bin/setclasspath.sh . 在catalina.sh文件和setclasspath.sh文 ...
- tomcat下jndi的三种配置方式
jndi(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API.命名服务将名称和对象联系起来,使得我们可以用 ...
- Mac下配置idk
Mac下配置java #以下进入啰嗦模式演示添加jdk7 #下载jdk7的mac版 #官网下载地址http://www.oracle.com/technetwork/java/javase/downl ...
- 什么是PHP Guzzle?
Guzzle是一个使得利用PHP实现发送HTTP 请求,方便和web service集成的PHP 客户端模拟组件.一句话,它就像一个PHP写的浏览器.当你的服务端程序需要作为客户端来访问其他的serv ...
- HDU 1372 (搜索方向稍有改变) Knight Moves
其实手写模拟一个队列也挺简单的,尤其是熟练以后. 尼玛,这题欺负我不懂国际象棋,后来百度了下,国际象棋里骑士的走法就是中国象棋里面的马 所以搜索就有八个方向 对了注意初始化标记数组的时候,不要把起点标 ...
- IOS中bounds和frame
* 用bounds和frame来修改尺寸是有一些小区别的 三.isEqual:方法 1> 系统会根据对象isEqual方法的返回值来决定两个对象是否相同 * 比如判断对象a和b是否相同,就会查看 ...
- hihoCoder #1176 : 欧拉路·一 (简单)
题意:给出n个岛,每个岛都有桥到达其他岛,且桥数可多可少(即使两岛有多桥),判断是否是欧拉路(即每条桥只能走一次,所有桥都能遍历1遍). 思路: 满足如下条件之一者即为欧拉路: 1.连通图,每个岛的度 ...
- Using newInstance() to Instantiate a Fragment(转)
I recently came across an interesting question on StackOverflow regarding Fragment instantiation: Wh ...
- Python argparse
http://songpengfei.iteye.com/blog/1440158 https://docs.python.org/2/library/argparse.html http://sta ...