四叉树

小Ho:朴素的想法是我用一个二维数组来把整个平面图表示出来。假设坐标的范围是L,那么就需要一个L*L的数组。

对于(a,b)和r,我就检查a-r到a+r行的b-r列到b+r列,看其中是否存在有点,并且点到(a,b)的距离是小于等于r的。

对于L超过10000的情况就没有办法实现了。

小Hi:没错,在坐标范围和点数都很大的情况下,确实会有这样的问题。

小Ho:我在想能不能把整个区域分割成若干的小区域,每次都在附近的小区域去找临近的点呢。

小Hi:小Ho你这个想法很棒,我们不妨来试试吧?

小Ho:那应该怎么分割呢?

小Hi:你还记得线段树么?在线段树的处理中,我们将一个区间从中点分成两段。这里我们也用同样的方法,将一个区域分割为4块好了:

从上到下,从左到右,分别标记为1234。

我们将所有的点放进这些区域中,为了让一个区域中点数不过多,我们设定一个区域的点数上限。

若一个区域的点数过多,我们就将这个区域四分,把新的点放到子区域中去。

小Ho:听上去好像很有道理。

小Hi:当然有道理了,这种数据结构叫做"四叉树(Quadtree)"。其每个基本单元为:

QuadtreeNode:
	const NODE_CAPACITY; // 每个节点包含的点数限制,常量
	boundary; // 该节点的范围,包含4个参数,区域的上下左右边界
	points; // 该区域内节点的列表
	childNode; // 包含4个参数,分别表示4个子区域

假设NODE_CAPACITY=1,那么我们可以把整个区域分割为:

小Ho:恩,这个我理解了,因为跟线段树差不多,那么也就是同样存在插入和查询操作了?

小Hi:没错。

四叉树的插入操作:将新的节点(x,y)插入时,若不在当前区域内,退出;否则将其加入该区域的节点列表points,若当前区域的节点列表已经满了。那么将该区域进行四分,同时将节点加入子区域中。

insert(QuadtreeNode nowNode, point p):
	If (p not in nowNode.boundary) Then
		Return
	End If
	If (nowNode.points.length < NODE_CAPACITY) Then
		nowNode.points.append(p)
	Else
		nowNode.divide() // 将区域四分
		For each childNode of nowNode
			insert(childNode, p)
		End For
	End If

四叉树的查询操作一般是求一个范围内的点,因此带入的参数也是一个区域range:

query(QuadtreeNode nowNode, range):
	If (QuadtreeNode.boundary does not intersect range) Then
		//该节点的区域与查询区域不相交
		Return empty
	End If
	For each p in nowNode.points
		If (p in range) Then
			pointsInRange.append(p)
		End For
	End For
	If (nowNode.isDivide) Then
		// 如果该区域有分割过,那么子区域中的节点也有可能在其中
		For each childNode of nowNode
			query(childNode, range)
		End For
	End If
	Return pointsInRange

题目:

描述

小Ho:下个周末我们打算去隔壁城市玩吧?

小Hi:反正来回也挺近的,好啊。

小Ho:那么我先来规划一下游玩路线吧。

小Ho打开了手机中的地图APP,把坐标移动到了隔壁的城市。各种各样的店铺显示在了街道的地图上。

小Hi:小Ho,你知道地图APP是怎么计算出你周围的店铺么?

小Ho:哎?没有想过哎。

小Hi:其实这也是个很有意思的问题呢。我们先把模型简化一下,假设有一张平面图,上面分布了N个点,第i个点的坐标为(x[i],y[i])。

小Ho:用点来代表店铺么?

小Hi:是的,然后假如我们所在的坐标为(a,b),那么以我们为中心半径为r的范围内(包含边上),有多少个点呢?

小Ho:感觉是个很有意思的问题呢,让我想一想。

提示:四叉树(Quadtree)

输入

第1行:2个整数N,M。1≤N≤50,000,0≤M≤5,000。

第2..N+1行:每行2个整数x,y,第i+1行表示第i个点的坐标,保证没有重复的点。0≤x,y≤30,000

第N+2..N+M+1行:每行3个整数a,b,r,表示询问的中心坐标(a,b),以及半径r。0≤a,b,r≤30,000

输出

第1..M行:每行1个整数,第i行表示以第i个询问的(x,y)为中心所包含的点数。

样例输入
2 2
1 1
2 2
2 2 1
2 2 2
样例输出
1
2

ac代码:
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<iostream>
  5 #include<cmath>
  6 using namespace std;
  7
  8 struct Area{
  9     int l,r,t,d;
 10 };
 11
 12 struct Point{
 13     int x,y;
 14 };
 15
 16 struct Node{
 17     Node *lt,*rt,*ld,*rd;
 18     Area A;
 19     int ct;
 20     Node(Area a){
 21         lt=rt=ld=rd=NULL;
 22         A.l=a.l;
 23         A.r=a.r;
 24         A.t=a.t;
 25         A.d=a.d;
 26         ct=0;
 27     }
 28 };
 29
 30 void inser(Node *&T,Area a,Point p){
 31     if (T==NULL) T=new Node(a);
 32     if ((T->A).l>p.x) return ;
 33     if ((T->A).r<p.x) return ;
 34     if ((T->A).d>p.y) return ;
 35     if ((T->A).t<p.y) return ;
 36     (T->ct)++;
 37     if (a.l==a.r&&a.t==a.d) return ;
 38     int x=(a.l+a.r)/2;
 39     int y=(a.t+a.d)/2;
 40     Area w;
 41     if (a.l==a.r){
 42         w.l=w.r=a.l;
 43         w.t=a.t;
 44         w.d=y+1;
 45         inser(T->lt,w,p);
 46         w.t=y;
 47         w.d=a.d;
 48         inser(T->ld,w,p);
 49     }
 50     else if (a.t==a.d){
 51         w.t=w.d=a.t;
 52         w.l=a.l;
 53         w.r=x;
 54         inser(T->lt,w,p);
 55         w.l=x+1;
 56         w.r=a.r;
 57         inser(T->rt,w,p);
 58     }
 59     else{
 60         w.l=a.l;
 61         w.t=a.t;
 62         w.d=y+1;
 63         w.r=x;
 64         inser(T->lt,w,p);
 65         w.l=x+1;
 66         w.t=a.t;
 67         w.d=y+1;
 68         w.r=a.r;
 69         inser(T->rt,w,p);
 70         w.l=a.l;
 71         w.t=y;
 72         w.d=a.d;
 73         w.r=x;
 74         inser(T->ld,w,p);
 75         w.l=x+1;
 76         w.t=y;
 77         w.d=a.d;
 78         w.r=a.r;
 79         inser(T->rd,w,p);
 80     }
 81 }
 82
 83 int Find(Node *T,Point p,int r){
 84
 85     if (T==NULL) return 0;
 86     if (T->ct==0) return 0;
 87     int flag=0;
 88     if (r*r-pow(p.x-(T->A).l,2)>=pow(p.y-(T->A).t,2)) flag++;
 89     if (r*r-pow(p.x-(T->A).l,2)>=pow(p.y-(T->A).d,2)) flag++;
 90     if (r*r-pow(p.x-(T->A).r,2)>=pow(p.y-(T->A).t,2)) flag++;
 91     if (r*r-pow(p.x-(T->A).r,2)>=pow(p.y-(T->A).d,2)) flag++;
 92     if (flag==0){
 93         if ((T->A).r<p.x-r) return 0;
 94         if ((T->A).l>p.x+r) return 0;
 95         if ((T->A).t<p.y-r) return 0;
 96         if ((T->A).d>p.y+r) return 0;
 97         if ((T->A).r<p.x){
 98             if ((T->A).d>p.y) return 0;
 99             if ((T->A).t<p.y) return 0;
100         }
101         if ((T->A).l>p.x){
102             if ((T->A).d>p.y) return 0;
103             if ((T->A).t<p.y) return 0;
104         }
105     }
106     if (flag==4) return T->ct;
107     return Find(T->lt,p,r)+Find(T->ld,p,r)+Find(T->rt,p,r)+Find(T->rd,p,r);
108 }
109
110
111 int main(){
112     Area a;
113     a.l=a.d=0;
114     a.r=a.t=30000;
115     Node *root;
116     root = new Node(a);
117     int n,m;
118     scanf("%d%d",&n,&m);
119     Point p;
120     while (n--){
121         scanf("%d%d",&p.x,&p.y);
122         inser(root,a,p);
123     }
124     while (m--){
125         int r;
126         scanf("%d%d%d",&p.x,&p.y,&r);
127         printf("%d\n",Find(root,p,r));
128     }
129 }
时间: 2024-10-11 05:59:11

四叉树的相关文章

四叉树算法原理与实现

一.原理 四叉树编码的基本思想是:首先将把一副图像或栅格地图( ,k>1,不足则补网)等分成四个一级字块,顺序为左上,右上,左下,右下:然后逐块检查其中所有格网属性值(或灰度值),若相同,则该字块不再分:若不同,则将该子块进一步分成四个二级子块:如此递归地分割,直到每个子块的属性或灰度均相等为止. 二.算法实现 1 //实现四叉树编码 2 3 #include"stdio.h" 4 void Qutree(int arysize,int level,float curary[]

Unity 遍历敌人——使用四叉树空间分区

最近看了<游戏编程模式>这本书,里面有一篇空间分区的文章,看了心里痒痒,决定去尝试实现一下.文章后面会给出整个学习参考的链接. 实现的效果如下,我们有一个很大的场景,场景有许许多多的敌人.红色的点代表是玩家,黑色的点代表是敌人.在这样的一个大量敌人的情景下,我们不可能在玩家或敌人寻找身边的攻击对象时穷尽所有的对象.因为我们要建立空间分区,只遍历某个对应区的对象.在图下中,红点中遍历红框中的黑点对象,其他一律不遍历. 接下来我直接放代码了,主要采用了四叉树,如果对于一些不懂的地方断点调试下就可以

[转]一个四叉树Demo学习

程序代码: http://www.codeproject.com/Articles/30535/A-Simple-QuadTree-Implementation-in-C 四叉树: using System; using System.Drawing; using System.Collections.Generic; using System.Diagnostics; namespace QuadTreeLib { /// <summary> /// A Quadtree is a stru

HTML5实现3D和2D可视化QuadTree四叉树碰撞检测

QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域.QuadTree常用于空间数据库索引,3D的椎体可见区域裁剪,甚至图片分析处理,我们今天介绍的是QuadTree最常被游戏领域使用到的碰撞检测.采用QuadTree算法将大大减少需要测试碰撞的次数,从而提高游戏刷新性能,本文例子基于HT for Web的Canvas拓扑图和WebGL的3D引擎组件,通过GraphView和Graph3dView共享同一数据模型DataModel,同时呈现Qua

BNUOJ 4049 四叉树

四叉树 Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main 四叉树是一种常用的数据结构,广泛应用于栅格数据(如地图数据.遥感图像)的压缩编码中.将四叉树扩展到三维就形成了八叉树,可实现三维信息的压缩存储.下面是它的实现原理: 如图是一个8*8图象,如果该图像所有元素都一样(都是0或都是1),就编码为0,再加上公共一样的元素(如01或00).如果不一样,

UVA 297 Quadtrees(四叉树建树、合并与遍历)

<span style="font-size: 18pt; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">K - </span><span style="color: blue; font-size: 18pt; font-family: Arial, Helvetica, sans-serif; background-color

回想四叉树LOD地形(上)

唉.~事实上这是在差点儿相同一年前实现的东西,但当时没作好记录.放了那么久了,假设不做点总结的话,好像有点对不起自己,于是·········还是做点什么吧. 我脑洞比較小,仅仅能大量參考"潘李亮"大神的四叉树LOD地形论文和一个叫做"曾涛"大神的代码实现,小弟在此先向诸位致敬了.以下分享本人实践之后的一点心得. 为什么要用LOD地形? 或许看完了传说中的"龙书"有关地形那章,你就知道了一个简单的地形系统是怎么实现的,无非就是依据高度图提供的高度信

HT for Web可视化QuadTree四叉树碰撞检测

QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域.QuadTree常用于空间数据库索引,3D的椎体可见区域裁剪,甚至图片分析处理,我们今天介绍的是QuadTree最常被游戏领域使用到的碰撞检测.采用QuadTree算法将大大减少需要测试碰撞的次数,从而提高游戏刷新性能,本文例子基于HT for Web的图形引擎,通过GraphView和Graph3dView共享同一数据模型DataModel,同时呈现QuadTree算法下的2D和3D碰撞视图

四叉树空间索引原理及其实现

今天依然在放假中,在此将以前在学校写的四叉树的东西拿出来和大家分享. 四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构.它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割.四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是GIS中常用的空间索引之一.常规四叉树的结构如图所示,地理空间对象都存储在叶子节点上,中间节点以及根节点不存储地理空间对象. 四叉树示意图 四叉树对于区域查询

四叉树搜索附近的人

现在很多的APP都有"附近的人"功能. 粗略的思考一下,用户在登录的时候会将自己的位置信息告诉服务器,服务器会记录一份用户的位置信息列表. 假设服务器里只有10个人,那么要找附近的人就很简单,只需写一个算距离的函数,然后依次遍历长度是10的位置信息列表,距离从近到远排序,返回排序后的列表即可. 那么如果服务器里有1千万人呢,或者几亿人呢,比如微信.这时再从头到尾遍历(复杂度O(n))就不适合了. 通常情况下会使用“四叉树”来构建这些大量的位置信息. 1.四叉树 顾名思义,四叉树是叶子节