K-D Tree
k-D Tree(KDT , k-Dimension Tree) 是一种可以 高效处理
在结点数
在算法竞赛的题目中,一般有
建树
k-D Tree 具有二叉搜索树的形态,二叉搜索树上的每个结点都对应
假设我们已经知道了
-
若当前超长方体中只有一个点,返回这个点。
-
选择一个维度,将当前超长方体按照这个维度分成两个超长方体。
-
选择切割点:在选择的维度上选择一个点,这一维度上的值小于这个点的归入一个超长方体(左子树),其余的归入另一个超长方体(右子树)。
-
将选择的点作为这棵子树的根节点,递归对分出的两个超长方体构建左右子树,维护子树的信息。
为了方便理解,我们举一个
其构建出 k-D Tree 的形态可能是这样的:
其中树上每个结点上的坐标是选择的分割点的坐标,非叶子结点旁的
这样的复杂度无法保证。对于
-
选择的维度要满足其内部点的分布的差异度最大,即每次选择的切割维度是方差最大的维度。
-
每次在维度上选择切割点时选择该维度上的 中位数,这样可以保证每次分成的左右子树大小尽量相等。
可以发现,使用优化
现在,构建 k-D Tree 时间复杂度的瓶颈在于快速选出一个维度上的中位数,并将在该维度上的值小于该中位数的置于中位数的左边,其余置于右边。如果每次都使用 sort
函数对该维度进行排序,时间复杂度是
我们来回顾一下快速排序的思想。每次我们选出一个数,将小于该数的置于该数的左边,大于该数的置于该数的右边,保证该数在排好序后正确的位置上,然后递归排序左侧和右侧的值。这样的期望复杂度是 algorithm
库中,有一个实现相同功能的函数 nth_element()
,要找到 s[l]
和 s[r]
之间的值按照排序规则 cmp
排序后在 s[mid]
位置上的值,并保证 s[mid]
左边的值小于 s[mid]
,右边的值大于 s[mid]
,只需写 nth_element(s+l,s+mid,s+r+1,cmp)
。
借助这种思想,构建 k-D Tree 时间复杂度是
插入/删除
如果维护的这个
我们引入一个重构常数
在插入一个
如果还有删除操作,则使用 惰性删除,即删除一个结点时打上删除标记,而保留其在 k-D Tree 上的位置。如果这样写,当未删除的结点数在以
类似于替罪羊树,带重构的 k-D Tree 的树高仍然是
邻域查询
给定平面上的
首先建出关于这
枚举每个结点,对于每个结点找到不等于该结点且距离最小的点,即可求出答案。每次暴力遍历 2-D Tree 上的每个结点的时间复杂度是
此外,还可以使用一种启发式搜索的方法,即若一个结点的两个子树都有可能包含答案,先在与查询点距离最近的一个子树中搜索答案。可以认为,查询点到子树对应的长方形的最近距离就是此题的估价函数。
注意:虽然以上使用的种种优化,但是使用 k-D Tree 单次查询最近点的时间复杂度最坏还是
给定平面上的
和上一道例题类似,从最近点对变成了
由于题目中强调的是无序点对,即交换前后两点的顺序后仍是相同的点对,则每个有序点对会被计算两次,那么读入的
高维空间上的操作
在一个初始值全为
-
1 x y A
:将坐标 上的数加上 。 -
2 x1 y1 x2 y2
:输出以 为左下角, 为右上角的矩形内(包括矩形边界)的数字和。
强制在线。内存限制 20M
。保证答案及所有过程量在 int
范围内。
20M 的空间卡掉了所有树套树,强制在线卡掉了 CDQ 分治,只能使用 k-D Tree。
构建 2-D Tree,支持两种操作:添加一个
在查询矩形区域内的所有点的权值和时,仍然需要记录子树内每一维度上的坐标的最大值和最小值。如果当前子树对应的矩形与所求矩形没有交点,则不继续搜索其子树;如果当前子树对应的矩形完全包含在所求矩形内,返回当前子树内所有点的权值和;否则,判断当前点是否在所求矩形内,更新答案并递归在左右子树中查找答案。
已经证明,如果在
习题
贡献者:@CCXXXI@minamimelon@kenlig@mgt@Chrogeek@Henry-ZHR@Rainboy@ouuan@Ir1d@Xeonacid
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用