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. C#Web异步操作封装

    using System; using System.Collections.Generic; using System.Web; namespace HttpAsync { /// <summ ...

  2. RESTful在asp.net webAPI下的PUT、POST实现,json传输实体

    1.put方式实现 使用的是firefox的插件:httpRequester 2.Post实现 同上, 传入json,后台得到实体: 3.post传入string字符串,注意,string传入的时候, ...

  3. 浏览器同步测试神器 — BrowserSync

    Browsersync 能让浏览器实时.快速响应文件更改(html.js.css.sass.less等)并自动刷新页面.更重要的是 Browsersync可以同时在PC.平板.手机等设备下进项调试,当 ...

  4. Thread Safe(线程安全)和None Thread Safe(NTS,非线程安全)之分

    Windows版的PHP从版本5.2.1开始有Thread Safe(线程安全)和None Thread Safe(NTS,非线程安全)之分,这两者不同在于何处?到底应该用哪种?这里做一个简单的介绍. ...

  5. LUA脚本调用C场景,使用C API访问脚本构造的表

    LUA调用C lua解析中集成了一些系统服务, 故脚本中可以访问系统资源, 例如, lua脚本可以调用文件系统接口, 可以调用数学库, 但是总存在一些lua脚本中访问不到的系统服务或者扩展功能, 如果 ...

  6. Access项目文件的版本控制

    简单记录一下使用MS Access SVN(以下简称AccessSVN)的步骤吧. AccessSVN在http://accesssvn.codeplex.com/,该产品的目的是:Access SV ...

  7. asp.net mvc4 System.Web.Optimization找不到引用

    在MVC4的开发中,如果创建的项目为空MVC项目,那么在App_Start目录下没有BundleConfig.cs项的内容,在手动添加时在整个库中都找不到:System.Web.Optimizatio ...

  8. 自动化环境robot framework安装中问题解决

    在搭建自动化环境的时候需要安装以下程序:

  9. C# UDP 连接通信 简单示例

    Udp.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using S ...

  10. 14. 星际争霸之php设计模式--状态模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...