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. 《linux内核设计与实现》读书笔记第三章

    第3章 进程管理 3.1 进程 1.进程 进程就是处于执行期的程序. 进程包括: 可执行程序代码 打开的文件 挂起的信号 内核内部数据 处理器状态 一个或多个具有内存映射的内存地址空间 一个或多个执行 ...

  2. centos 6.7下 elasticsearch的安装

    1.下载elasticsearch的安装包,用ftp上传到linux系统下目录中,如在当前用户root的目录下新建目录elasticsearch,放入安装包 不要忘了添加执行权限 chmod +x * ...

  3. ExtJs 使用点滴 十三 在FormPanel 嵌入按钮

    Ext.onReady(function () { //初始化标签中的Ext:Qtip属性. Ext.QuickTips.init(); Ext.form.Field.prototype.msgTar ...

  4. Java学习-041-颜色工具类(RGB,HEX)

    在日常的网页开发中,经常需要进行颜色数值获取.转换,例如获取红色,获取蓝色,获取绿色,RGB转十六进制颜色,十六进制颜色转RGB等,因而在学习过程中,写了一个小工具类,仅供各位小主参考! 多不闲言,直 ...

  5. Convert and Cast for Date and Money format.

    SELECT REPLACE(REPLACE(@str, CHAR(13), ''), CHAR(10), '') The below script removes the TAB(Horozonta ...

  6. Java提高篇——equals()方法和“==”运算符

    equals() 超类Object中有这个equals()方法,该方法主要用于比较两个对象是否相等.该方法的源码如下: public boolean equals(Object obj) { retu ...

  7. Python基础一. 简介、变量、对象及引用

    一.Python简介 Python是一门计算机编程语言,它是由荷兰人Guido van Rossum在1989年圣诞节期间为了打发无聊的圣诞节而编写的,作为ABC语言的继承 特性: 面向对象.解释型. ...

  8. smartdraw2013破解方法

    smartdraw是一个非常好的画图工作,最大的优点就是支持多种图形,采用模板的方式在线扩充,可以快速画出你想要的图形,具体的介绍见其他资料. 这里是我自己的破解办法. 网上的下载都包含破解工具,但是 ...

  9. div显示滚动条

    div显示上下左右滚动条 <div style="width:260px;height:120px; overflow:scroll; border:1px solid;"& ...

  10. Eclipse中使用自己封装的jar包的过程

    在包名上右键,选择Export"" 经过上面的步骤,成功导出了可运行jar包,下面在另一个自己的工程里引入这个jar包 最终效果如下:可见包已经可以正常使用了!! 运行自己的jar ...