https://zhuanlan.zhihu.com/p/22557068

http://blog.csdn.net/zhjchengfeng5/article/details/7855241

KD树在算法竞赛中主要用来做各种各样的平面区域查询,包含则累加直接返回,相交则继续递归,相离的没有任何贡献也直接返回。可以处理圆,三角形,矩形等判断起来相对容易的平面区域内的符合加法性质的操作。

比如查询平面内欧几里得距离最近的点的距离。

kdtree其实有点像搜索,暴力+剪枝。

每次从根结点向下搜索,并进行剪枝操作,判断是否有必要继续搜索。

它是通过横一刀,竖一刀,横一刀再竖一刀将平面进行分割,建立二叉树。

建树的复杂度是O(nlogn), 每次用nth_element()在线性时间内取出中位数。 T(n) = 2T(n/2) + O(n) = O(nlogn)

查询复杂度呢? 据第二个链接的博客说最坏是O( sqrt(n) ) 的。并不会分析查询复杂度。

HDU2966 裸kdtree

题意:给平面图上N(1 ≤ N ≤100000)个点,对每个点,找到其他 欧几里德距离 离他最近的点,输出他们之间的距离。保证没有重点。

 #include <bits/stdc++.h>
#define ll long long
using namespace std;
#define N 200010
const ll inf = 1e18;
int n,i,id[N],root,cmp_d;
int x, y;
struct node{int d[],l,r,Max[],Min[],val,sum,f;}t[N];
bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
void umax(int&a,int b){if(a<b)a=b;}
void umin(int&a,int b){if(a>b)a=b;}
void up(int x){
if(t[x].l){
umax(t[x].Max[],t[t[x].l].Max[]);
umin(t[x].Min[],t[t[x].l].Min[]);
umax(t[x].Max[],t[t[x].l].Max[]);
umin(t[x].Min[],t[t[x].l].Min[]);
}
if(t[x].r){
umax(t[x].Max[],t[t[x].r].Max[]);
umin(t[x].Min[],t[t[x].r].Min[]);
umax(t[x].Max[],t[t[x].r].Max[]);
umin(t[x].Min[],t[t[x].r].Min[]);
}
}
int build(int l,int r,int D,int f){
int mid=(l+r)>>;
cmp_d=D,std::nth_element(t+l,t+mid,t+r+,cmp);
id[t[mid].f]=mid;
t[mid].f=f;
t[mid].Max[]=t[mid].Min[]=t[mid].d[];
t[mid].Max[]=t[mid].Min[]=t[mid].d[];
//t[mid].val=t[mid].sum=0;
if(l!=mid)t[mid].l=build(l,mid-,!D,mid);else t[mid].l=;
if(r!=mid)t[mid].r=build(mid+,r,!D,mid);else t[mid].r=;
return up(mid),mid;
} ll dis(ll x1, ll y1, ll x, ll y) {
ll xx = x1-x, yy = y1-y;
return xx*xx+yy*yy;
}
ll dis(int p, ll x, ll y){//估价函数, 以p为子树的最小距离
ll xx = , yy = ;
if(t[p].Max[] < x) xx = x-t[p].Max[];
if(t[p].Min[] > x) xx = t[p].Min[]-x;
if(t[p].Max[] < y) yy = y-t[p].Max[];
if(t[p].Min[] > y) yy = t[p].Min[]-y;
return xx*xx+yy*yy;
}
ll ans;
void query(int p){
ll dl = inf, dr = inf, d = dis(t[p].d[], t[p].d[], x, y);
if(d) ans = min(ans, d); if(t[p].l) dl = dis(t[p].l, x, y);
if(t[p].r) dr = dis(t[p].r, x, y);
if(dl < dr){
if(dl < ans) query(t[p].l);
if(dr < ans) query(t[p].r);
}
else {
if(dr < ans) query(t[p].r);
if(dl < ans) query(t[p].l);
}
} int main(){
int T; scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i = ; i <= n; i++){
scanf("%d%d", &t[i].d[], &t[i].d[]);
t[i].f = i;
}
int rt = build(, n, , );
for(int i = ; i <= n; i++){
ans = inf;
x = t[ id[i] ].d[], y = t[ id[i] ].d[];
query(rt);
printf("%lld\n", ans);
}
}
return ;
}

BZOJ2648

题意:给出n个点,接下来m个操作,每次插入一个点,或者询问离询问点的最近曼哈顿距离。

 #include <bits/stdc++.h>
#define ll long long
using namespace std;
#define N 1000010
const ll inf = 1e18;
int n,m,i,id[N],root,cmp_d,rt;
int x, y;
struct node{int d[],l,r,Max[],Min[],val,sum,f;}t[N];
bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
void umax(int&a,int b){if(a<b)a=b;}
void umin(int&a,int b){if(a>b)a=b;}
void up(int x){
if(t[x].l){
umax(t[x].Max[],t[t[x].l].Max[]);
umin(t[x].Min[],t[t[x].l].Min[]);
umax(t[x].Max[],t[t[x].l].Max[]);
umin(t[x].Min[],t[t[x].l].Min[]);
}
if(t[x].r){
umax(t[x].Max[],t[t[x].r].Max[]);
umin(t[x].Min[],t[t[x].r].Min[]);
umax(t[x].Max[],t[t[x].r].Max[]);
umin(t[x].Min[],t[t[x].r].Min[]);
}
}
int build(int l,int r,int D,int f){
int mid=(l+r)>>;
cmp_d=D,std::nth_element(t+l,t+mid,t+r+,cmp);
id[t[mid].f]=mid;
t[mid].f=f;
t[mid].Max[]=t[mid].Min[]=t[mid].d[];
t[mid].Max[]=t[mid].Min[]=t[mid].d[];
//t[mid].val=t[mid].sum=0;
if(l!=mid)t[mid].l=build(l,mid-,!D,mid);else t[mid].l=;
if(r!=mid)t[mid].r=build(mid+,r,!D,mid);else t[mid].r=;
return up(mid),mid;
} ll dis(ll x1, ll y1, ll x, ll y) {
return abs(x1-x)+abs(y1-y);
//ll xx = x1-x, yy = y1-y;
//return xx*xx+yy*yy;
}
ll dis(int p, ll x, ll y){//估价函数, 以p为子树的最小距离
ll xx = , yy = ;
if(t[p].Max[] < x) xx = x-t[p].Max[];
if(t[p].Min[] > x) xx = t[p].Min[]-x;
if(t[p].Max[] < y) yy = y-t[p].Max[];
if(t[p].Min[] > y) yy = t[p].Min[]-y;
return xx+yy;
//return xx*xx+yy*yy;
}
ll ans;
void ins(int now, int k, int x){
if(t[x].d[k] >= t[now].d[k]){
if(t[now].r) ins(t[now].r, !k, x);
else
t[now].r = x, t[x].f = now;
}
else {
if(t[now].l) ins(t[now].l, !k, x);
else t[now].l = x, t[x].f = now;
}
up(now);
}
void query(int p){
ll dl = inf, dr = inf, d = dis(t[p].d[], t[p].d[], x, y);
ans = min(ans, d); if(t[p].l) dl = dis(t[p].l, x, y);
if(t[p].r) dr = dis(t[p].r, x, y);
if(dl < dr){
if(dl < ans) query(t[p].l);
if(dr < ans) query(t[p].r);
}
else {
if(dr < ans) query(t[p].r);
if(dl < ans) query(t[p].l);
}
} int main(){
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++)
scanf("%d%d", &t[i].d[], &t[i].d[]);
rt = build(, n, , );
while(m--){
int op;
scanf("%d%d%d", &op, &x, &y);
if(op == ){
n++;
t[n].l = t[n].r = ;
t[n].Max[] = t[n].Min[] = t[n].d[] = x;
t[n].Max[] = t[n].Min[] = t[n].d[] = y;
ins(rt, , n);
}
else{
ans = inf;
query(rt);
printf("%lld\n", ans);
}
}
return ;
}

BZOJ3053

题意:k维坐标系下的最近的m个点。直接对于每一个询问都在kdtree中询问m次最近点,每次找到一个最近点对需要把它记录下来,用堆维护即可。

 #include <bits/stdc++.h>
#define ll long long
#define mp make_pair using namespace std;
#define N 50010
const ll inf = 1e18;
int n,m,k,i,id[N],root,cmp_d,rt;
int x, y, num;
struct node{int d[],l,r,Max[],Min[],val,sum,f;}t[N];
bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
void umax(int&a,int b){if(a<b)a=b;}
void umin(int&a,int b){if(a>b)a=b;}
void up(int x){
for(int i = ; i < k; i++){
if(t[x].l){
umax(t[x].Max[i],t[t[x].l].Max[i]);
umin(t[x].Min[i],t[t[x].l].Min[i]);
}
if(t[x].r){
umax(t[x].Max[i],t[t[x].r].Max[i]);
umin(t[x].Min[i],t[t[x].r].Min[i]);
}
}
}
int build(int l,int r,int D,int f){
int mid=(l+r)>>;
cmp_d=D,std::nth_element(t+l,t+mid,t+r+,cmp);
id[t[mid].f]=mid;
t[mid].f=f;
for(int i = ; i < k; i++)
t[mid].Max[i]=t[mid].Min[i]=t[mid].d[i];
//t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1];
//t[mid].val=t[mid].sum=0;
if(l!=mid)t[mid].l=build(l,mid-,(D+)%k,mid);else t[mid].l=;
if(r!=mid)t[mid].r=build(mid+,r,(D+)%k,mid);else t[mid].r=;
return up(mid),mid;
}
int qx[];
ll dis(int p){//估价函数, 以p为子树的最小距离
ll ret = , ans = ;
for(int i = ; i < k; i++) {
ret = ;
if(t[p].Max[i] < qx[i]) ret = qx[i]-t[p].Max[i];
if(t[p].Min[i] > qx[i]) ret = t[p].Min[i]-qx[i];
ans += ret*ret;
}
return ans;
}
ll getdis(int p){
ll ans = ;
for(int i = ; i < k; i++)
ans += (qx[i]-t[p].d[i])*(qx[i]-t[p].d[i]);
return ans;
}
void ins(int now, int k, int x){
if(t[x].d[k] >= t[now].d[k]){
if(t[now].r) ins(t[now].r, !k, x);
else
t[now].r = x, t[x].f = now;
}
else {
if(t[now].l) ins(t[now].l, !k, x);
else t[now].l = x, t[x].f = now;
}
up(now);
}
ll ret;
multiset< pair<int, int> > ans;
void query(int p){
ll dl = inf, dr = inf, d = getdis(p);
ans.insert( mp((int)d, p) );
if(ans.size() > num){
multiset< pair<int, int> >::iterator it = ans.end();
it--;
ans.erase(it);
}
ret = (*ans.rbegin()).first;
if(t[p].l) dl = dis(t[p].l);
if(t[p].r) dr = dis(t[p].r);
if(dl < dr){
if(dl < ret||ans.size() < num) query(t[p].l);
if(dr < ret||ans.size() < num) query(t[p].r);
}
else {
if(dr < ret||ans.size() < num) query(t[p].r);
if(dl < ret||ans.size() < num) query(t[p].l);
}
} int main(){
while(~scanf("%d%d", &n, &k)){
for(int i = ; i <= n; i++){
for(int j = ; j < k; j++)
scanf("%d", &t[i].d[j]);
}
rt = build(, n, , );
scanf("%d", &m);
while(m--){
for(int i = ; i < k; i++)
scanf("%d", qx+i);
scanf("%d", &num);
ans.clear();
query(rt);
printf ("the closest %d points are:\n", num);
for(multiset< pair<int, int> >::iterator it = ans.begin(); it != ans.end(); it++){
int pos = (*it).second;
for(int i = ; i < k; i++)
printf("%d%c", t[pos].d[i], " \n"[i == k-]);
}
}
}
return ;
}

kd tree学习笔记 (最近邻域查询)的更多相关文章

  1. k-d tree 学习笔记

    以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...

  2. K-D Tree学习笔记

    用途 做各种二维三维四维偏序等等. 代替空间巨大的树套树. 数据较弱的时候水分. 思想 我们发现平衡树这种东西功能强大,然而只能做一维上的询问修改,显得美中不足. 于是我们尝试用平衡树的这种二叉树结构 ...

  3. MyBatis:学习笔记(3)——关联查询

    MyBatis:学习笔记(3)--关联查询 关联查询 理解联结 SQL最强大的功能之一在于我们可以在数据查询的执行中可以使用联结,来将多个表中的数据作为整体进行筛选. 模拟一个简单的在线商品购物系统, ...

  4. mybatis学习笔记(10)-一对一查询

    mybatis学习笔记(10)-一对一查询 标签: mybatis mybatis学习笔记10-一对一查询 resultType实现 resultMap实现 resultType和resultMap实 ...

  5. 珂朵莉树(Chtholly Tree)学习笔记

    珂朵莉树(Chtholly Tree)学习笔记 珂朵莉树原理 其原理在于运用一颗树(set,treap,splay......)其中要求所有元素有序,并且支持基本的操作(删除,添加,查找......) ...

  6. dsu on tree学习笔记

    前言 一次模拟赛的\(T3\):传送门 只会\(O(n^2)\)的我就\(gg\)了,并且对于题解提供的\(\text{dsu on tree}\)的做法一脸懵逼. 看网上的其他大佬写的笔记,我自己画 ...

  7. SQLServer学习笔记<>相关子查询及复杂查询

    二.查询缺少值的查询 在这里我们加入要查询2008年每一天的订单有多少?首先我们可以查询下订单表的订单日期在2008年的所有订单信息. 1 select distinct orderdate,coun ...

  8. Hibernate学习笔记-Hibernate HQL查询

    Session是持久层操作的基础,相当于JDBC中的Connection,通过Session会话来保存.更新.查找数据.session是Hibernate运作的中心,对象的生命周期.事务的管理.数据库 ...

  9. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

随机推荐

  1. Unity Svn(转)

    先吐个槽.关于这个国内各种简单到家的文章让人搞不懂,而且场景合并,prefab合并等关键问题都说没法解决,其实本质就是因为它们都是二进制文件,所以SVN没法对其合并,但事实上Unity是支持把这些文件 ...

  2. 【转】Unity中的协同程序-使用Promise进行封装(一)

    原文:http://gad.qq.com/program/translateview/7170767 译者:陈敬凤(nunu)    审校:王磊(未来的未来) 每个Unity的开发者应该都对协同程序非 ...

  3. UIView常见属性设置汇总

    1.圆角设置 viewT.layer.cornerRadius = 10;//设置那个圆角的有多圆 viewT.layer.borderWidth = 10;//设置边框的宽度,当然可以不要 view ...

  4. request.querystring和request.form、session的区别

    1. request.querystring是用来接收地址里面问号“?”后面的参数的内容,  用get方法读取的 不安全   request.form是用来接收表单递交来的数据 ,是用post方法读取 ...

  5. RML Utilities for SQL Server

    很早以前有看到过关于使用RML Utilities工具分析SQL Trace(.trc)的文章,但一直没有具体实践.最近接管一台数据库服务器,跟踪出一批高消耗的语句,老大需要跟踪分析报表,罗列出过程( ...

  6. pod install出现[!] /bin/bash -c错误,Installing Realm报错

    pod install出现错误,具体错误信息如下: Installing Realm () [!] /bin/bash -c set -e sh build.sh cocoapods-setup co ...

  7. SpringMVC源码剖析(一)- 从抽象和接口说起

    SpringMVC作为Struts2之后异军突起的一个表现层框架,正越来越流行,相信javaee的开发者们就算没使用过SpringMVC,也应该对其略有耳闻.我试图通过对SpringMVC的设计思想和 ...

  8. electron开发(一)

    0. 简介 http://electron.atom.io/ 官网 https://www.v2ex.com/t/277623   基于 Electron 的 Linux 下的网易云音乐 https: ...

  9. @Override的作用

    @Override是伪代码,表示重写(不写也可以,但是有些IDE会报warning),不过写上有如下好处: 1.可以当注释用,方便阅读:2.编译器可以给你验证@Override下面的方法名是否是你父类 ...

  10. final关键字用法总结

    在java中,可能使用到final关键字修饰的有数据.方法和类. 一.final 修饰数据 有final修饰的数据是用来告诉编译器一块数据是恒定不变的,有时数据恒定不变是很有用的,比如: 1.一个永不 ...