KDtree浅谈

1.对KDtree的理解

  首先要知道$KDtree$的用处,$KDtree$是用来进行多维数点的,一般这些点都是在在而二维及二维以上,因为一维上的问题,我们基本都可以运用线段树来解决。我对$KDtree$的理解就是一个自带剪枝的暴力,并且这个剪枝因为我们对这些多维上的点的较优秀的排列而显得十分有用。

2.前置知识

  在学习$KDtree$之前要先知道并会运用西面三个知识点:

​  1) 首先,要会建二叉搜索树,因为整个$KDtree$就是一颗二叉搜索树。

  2) 还需要知道什么事估价函数,因为剪枝的时候要运用到估价函数。

​  3) 对空间的想象能力,因为$KDtree$是处理图形上的问题,所以还需要有一定的空间想象能力。

3.KDTree的讲解

  因为$KDtree$是一种优美的暴力,并且我们要在上面剪枝,所以我们自然想让每一次剪枝,剪下去尽可能大的部分,所以我们能想到每一次将区间等大的分割,既然要的等大的分割,又要是二叉搜索树,我们就要让中间值作为当前节点,所有比它小的都放在它的左面,比它大的都放在它的右面。

  知道大致思路了,就要来定义什么是大小了,因为一个点是在多维里,所以和它有关的值有多个。最好想的就是按读入的顺序,进行排序,第一维作为第一关键字,第二维作为第二关键字,以此类推。我们根据这些点的维度将它们从小到大排序(下面已二维上的点为例),每一次取当前区间的中间值来建树。这样我们就能将整个图分成下面的形式:

  显然这种分法分出的图并不是最有利,因为每一点的管辖范围都太小了。我们考虑另一种分割方式,我们将这些点的排序方式进行改变,我们将排序的关键字每一次向顺时针进行转动,即我们第一次排序的第一关键字是第一维,第二次是第二维……第$n$次是第$n\%维数+1$维。这样上面的图形就可以改变成为:

  这样我们在剪枝的时候就能剪去更多的节点。

  知道了如何去排序,我们现在就要知道怎么来找中间值。在函数库里面有一个函数$nth\_element$,这个就能实现我们要的功能。这个函数不知道实现的话,可以上网上找一下学习一下。我们在建树的时候要维护出来几个值,这几个值的运用在下面会进行讲解。这几个值是$mn[0],mx[0],mn[1],mx[1]$,分别表示以当前节点为根的子树第一维的最小值和最大值,第二维的最小值和最大值,这样我们在建树的时候应该更新。

struct Node {long long pla[2],mn[2],mx[2];int id,lson,rson;}node[N];
bool cmp(const Node &a,const Node &b) {return a.pla[sta]<b.pla[sta];}
void up(int p,int k)
{
node[p].mn[0]=min(node[p].mn[0],node[k].mn[0]);
node[p].mx[0]=max(node[p].mx[0],node[k].mx[0]);
node[p].mn[1]=min(node[p].mn[1],node[k].mn[1]);
node[p].mx[1]=max(node[p].mx[1],node[k].mx[1]);
}
int build(int l,int r,int now)
{
sta=now;int mid=(l+r)>>1;
nth_element(node+l,node+mid,node+r+1,cmp);
node[mid].mn[0]=node[mid].mx[0]=node[mid].pla[0];
node[mid].mn[1]=node[mid].mx[1]=node[mid].pla[1];
if(l!=mid) node[mid].lson=build(l,mid-1,(now+1)%2);
if(r!=mid) node[mid].rson=build(mid+1,r,(now+1)%2);
if(node[mid].lson) up(mid,node[mid].lson);
if(node[mid].rson) up(mid,node[mid].rson);
return mid;
}

  建树之后,我们就可以在里面进行一些操作,比如找离定点的最远点,最近点,维护矩形内信息等等,下面就是一些估价函数的代码,以及矩形内区间赋值。

  找离当前点的最近点的估价函数及查询(欧几里得距离):

long long dis(int p) {return squ(node[p].pla[0]-x)+squ(node[p].pla[1]-y);}
long long getdis(int p)
{
long long tmp=0;
tmp+=squ(max(abs(node[p].mx[0]-x),abs(node[p].mn[0]-x)));
tmp+=squ(max(abs(node[p].mx[1]-y),abs(node[p].mn[1]-y)));
return tmp;
}
void ask(int p)
{
long long tmp=dis(p);tmpx.dis=tmp,tmpx.id=node[p].id;
if(q.top().dis<=tmpx.dis) q.push(tmpx),q.pop();
long long tmpl=(node[p].lson)?getdis(node[p].lson):-inf;
long long tmpr=(node[p].rson)?getdis(node[p].rson):-inf;
if(tmpl>tmpr)
{
if(tmpl>=q.top().dis&&node[p].lson) ask(node[p].lson);
if(tmpr>=q.top().dis&&node[p].rson) ask(node[p].rson);
}
else
{
if(tmpr>=q.top().dis&&node[p].rson) ask(node[p].rson);
if(tmpl>=q.top().dis&&node[p].lson) ask(node[p].lson);
}
}

  找离当前点的最远点的估价函数及查询(曼哈顿距离):

int getdis_mx(int p)
{
int tmp=0;
tmp+=max(abs(node[p].mx[0]-x),abs(node[p].mn[0]-x));
tmp+=max(abs(node[p].mx[1]-y),abs(node[p].mn[1]-y));
return tmp;
}
void ask_mx(int p)
{
int tmp=abs(node[p].pla[0]-x)+abs(node[p].pla[1]-y);
if(tmp>lenth_mx) lenth_mx=tmp;
int tmpl=(node[p].lson)?(getdis_mx(node[p].lson)):-inf;
int tmpr=(node[p].rson)?(getdis_mx(node[p].rson)):-inf;
if(tmpl>tmpr)
{
if(tmpl>lenth_mx) ask_mx(node[p].lson);
if(tmpr>lenth_mx) ask_mx(node[p].rson);
}
else
{
if(tmpr>lenth_mx) ask_mx(node[p].rson);
if(tmpl>lenth_mx) ask_mx(node[p].lson);
}
}

  找离当前点的最远点的估价函数及查询(曼哈顿距离):

int getdis_mn(int p)
{
int tmp=0;
if(x<node[p].mn[0]) tmp+=node[p].mn[0]-x;
if(x>node[p].mx[0]) tmp+=x-node[p].mx[0];
if(y<node[p].mn[1]) tmp+=node[p].mn[1]-y;
if(y>node[p].mx[1]) tmp+=y-node[p].mx[1];
return tmp;
}
void ask_mn(int p)
{
int tmp=abs(node[p].pla[0]-x)+abs(node[p].pla[1]-y);
if(tmp&&tmp<lenth_mn) lenth_mn=tmp;
int tmpl=(node[p].lson)?(getdis_mn(node[p].lson)):inf;
int tmpr=(node[p].rson)?(getdis_mn(node[p].rson)):inf;
if(tmpl<tmpr)
{
if(tmpl<lenth_mn) ask_mn(node[p].lson);
if(tmpr<lenth_mn) ask_mn(node[p].rson);
}
else
{
if(tmpr<lenth_mn) ask_mn(node[p].rson);
if(tmpl<lenth_mn) ask_mn(node[p].lson);
}
}

  矩阵赋值,矩阵查找:

void pushdown(int p)
{
if(!node[p].tag) return;
if(node[p].lson) node[node[p].lson].tag=node[node[p].lson].col=node[p].tag;
if(node[p].rson) node[node[p].rson].tag=node[node[p].rson].col=node[p].tag;
node[p].tag=0;
}
void change(int p,int w,int x,int y,int z,int col)
{
if(!p) return;
if(node[p].mx[0]<w||node[p].mn[0]>x) return;
if(node[p].mx[1]<y||node[p].mn[1]>z) return;
pushdown(p);
if(node[p].pla[0]>=w&&node[p].pla[0]<=x&&
node[p].pla[1]>=y&&node[p].pla[1]<=z) node[p].col=col;
if(node[p].mn[0]>=w&&node[p].mx[0]<=x&&
node[p].mn[1]>=y&&node[p].mx[1]<=z) {node[p].tag=node[p].col=col;return;}
change(node[p].lson,w,x,y,z,col),change(node[p].rson,w,x,y,z,col);
}
int find(int p,int w,int x,int y,int z)
{
if(!p) return 0;
if(node[p].mx[0]<w||node[p].mn[0]>x) return 0;
if(node[p].mx[1]<y||node[p].mn[1]>z) return 0;
pushdown(p);
if(node[p].pla[0]==w&&node[p].pla[1]==y) return node[p].col;
return max(find(node[p].lson,w,x,y,z),find(node[p].rson,w,x,y,z));
}

KDtree浅谈的更多相关文章

  1. cdq分治浅谈

    $cdq$分治浅谈 1.分治思想 分治实际上是一种思想,这种思想就是将一个大问题划分成为一些小问题,并且这些小问题与这个大问题在某中意义上是等价的. 2.普通分治与$cdq$分治的区别 普通分治与$c ...

  2. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  3. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  4. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  5. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

  6. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  7. 浅谈angular2+ionic2

    浅谈angular2+ionic2   前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别.   1. 项目所用:angular2+ionic2 ...

  8. iOS开发之浅谈MVVM的架构设计与团队协作

    今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  9. Linux特殊符号浅谈

    Linux特殊字符浅谈 我们经常跟键盘上面那些特殊符号比如(?.!.~...)打交道,其实在Linux有其独特的含义,大致可以分为三类:Linux特殊符号.通配符.正则表达式. Linux特殊符号又可 ...

随机推荐

  1. Pascal小游戏 井字棋

    一个很经典的井字棋游戏 Pascal源码Chaobs奉上 注意:1.有的FP版本不支持汉语,将会出现乱码.2.别想赢电脑了,平手不错了. 井字过三关: program TicTacToe; uses ...

  2. iOS笔记057 - UI总结03

    控制器的父子关系 1.控制器父子关系的建立原则        如果2个控制器的view是父子关系(不管是直接还是间接的父子关系),那么这2个控制器也应该为父子关系 [self.view addSubv ...

  3. 孤荷凌寒自学python第十三天python代码的外部模块引用与基本赋值语句

    孤荷凌寒自学python第十三天python代码的外部模块引用与基本赋值语句 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 从结构化编程流行以来,代码便被分块存储,称之为模块或库. 在pyt ...

  4. Where can I find the IPA logs

    Retrieving the IPA logs will differ depending on which base image was used. Operating system that do ...

  5. Ubuntu16.04安装openCV的问题集合

    Q1 下列软件包有未满足的依赖关系:   libtiff4-dev : 依赖: libjpeg-dev  E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系. 上网查了 ...

  6. Opencv3.2.0安装包

    这个资源是Opencv3.2.0安装包,包括Windows软件包,Android软件包,IOS软件包,还有opencv的源代码:需要的下载吧. 点击下载

  7. HDU 4116 Fruit Ninja ( 计算几何 + 扫描线 )

    给你最多1000个圆,问画一条直线最多能与几个圆相交,相切也算. 显然临界条件是这条线是某两圆的公切线,最容易想到的就是每两两圆求出所有公切线,暴力判断一下. 可惜圆有1000个,时间复杂度太高. 网 ...

  8. 201621123033 《Java程序设计》第3周学习总结

    第三周作业 1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识点组织起来.请使用工具画出本周学习到的知识点及知识点之间的联系.步骤如下: 1 ...

  9. [codevs1746][NOI2002]贪吃的九头龙

    [codevs1746][NOI2002]贪吃的九头龙 试题描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时 ...

  10. 泛型与非泛型集合类的区别及使用例程,包括ArrayList,Hashtable,List<T>,Dictionary<Tkey,Tvalue>,SortedList<Tkey,Tvalue>,Queue<T>,Stack<T>等

    泛型与非泛型集合类在C#程序中是非常重要的一个基础概念,这里列一个表来进行对比: 非泛型集合类 泛型集合类 描述 ArrayList List<T> 表示具有动态大小的对象数组 Hasht ...