K-D Tree

K-D Tree (K - Dimension Tree),是一种用来解决 \(k\) 维空间信息的数据结构;一般在 OI 竞赛中,以 \(k=2\) 为多

K-D Tree 实际上是一个二叉搜索树;而为了让复杂度尽量优(注意,K-D Tree 在某些问题可以被卡成暴力的复杂度),我们会让树高尽可能的小,因此它也属于“平衡树”的一种


建树

  1. 我们先按照某些方法,从 \(k\) 维选出某一维 \(i\)

  2. 然后将点按照第 \(i\) 维排序,选出该维度上的中位数的点 \(u\),将 \(u\) 作为当前子树的根;

  3. 对于 \(\le u_i\)\(u\) 在第 \(i\) 维的坐标)的点,分到左子树;\(> u_i\) 的点,分到右子树;

  4. 重复步骤 \(1\)

对于步骤 \(1\) 维度的选取方法,我们有以下可选项:

  1. \(rand()\bmod k\)

  2. 假设上一次选取的是 \(p\),那么这次选 \((p+1)\bmod k\)

  3. 选择方差最大的维度

一般来说,第三种方法是最优的方案,证明可以见《kdtree划分空间维度选择使用“最大方差法”的好处》

再来看步骤 \(3\),如果我们直接排序,复杂度将会多带一个 \(\log n\),而其实我们只关心分到左右哪边,而不需要确切的顺序,因此可以使用 nth_element

建好树了,那这个东西到底有什么用呢?通过几道例题来了解一下:


P4357 [CQOI2016]K 远点对

先直接建树,同时,对于每个子树的根节点,我们都要记录子树内最大的 \(x,y\) 值和最小的 \(x,y\)

然后我们考虑每个点都跑一次 query,具体过程如下:

假设我们现在到达了结点 \(u\),计算 \(u\) 到枚举的点的距离,更新答案

然后,我们计算左子树到枚举的点的最远可能距离 \(Ld\),以及右子树到枚举的点的最远可能距离 \(Rd\)

我们将 \(Ld\) 与目前的第 \(k\) 远进行比较,如果 \(Ld>\)\(k\) 远,就递归到左子树;右子树同理

然后有一个小优化,就是如果 \(Ld>Rd\),我们优先递归左子树;反之优先递归右子树

代码


P4148 简单题

这道题要求强制在线,且内存只有 \(20\text{MB}\),杀掉许多的 cdq 分治、树套树

但时限有足足 8s,给够了 K-D Tree 时间

先不管加权,先来做查询:我们每个结点还都记录子树内最大的 \(x,y\) 和 最小的 \(x,y\),这四个值恰好组成一个最大可能矩形

当询问一个矩形 \(M\) 时,我们与每个结点 \(u\) 比较:如果 \(M\) 包含\(u\) 的最大可能矩形,那么我们将这整个子树的权值和都计入答案,并不用再递归;如果 \(M\)\(u\) 的最大可能矩形相离,那么直接返回;如果是有相交,那么我们就判断 \(u\) 是否计入答案,然后递归左右子树

再来看加权操作,其实我们可以看作每次都新增一个结点

我们按照二叉搜索树的方法将点加入

但这可能导致树高不正确,使得被卡回暴力

因此,我们在这里引入替罪羊树暴力重建的思想:对于一个子树 \(u\),如果 \(\text{sz}_u * \alpha\) 小于左或右子树的大小,那么我们就将子树 \(u\) 重建。一般而言,\(\alpha \in [0.6,~0.7]\)

代码


练习题

P4390 [BOI2007]Mokia 摩基亚
(与上一题一模一样,但没有了强制在线,要不用 cdq 试一试?)

P2479 [SDOI2010]捉迷藏
(求最近和最远点对,曼哈顿距离)

P6224 [BJWC2014]数据
(与上一题类似,不过带有插入新节点)


进阶

P3769 [CH弱省胡策R2]TATT

四维偏序问题,考虑将一维进行排序

朴素的 DP 转移方程:

\[f_i=\max\{f_j+1\}[a_j\le a_i,~b_j\le b_i,~c_j\le c_i,~d_j\le d_i] \]

我们每次转移就从 K-D Tree 上找最大值,更新 \(f_i\) 后就把点 \(i\) 加到 K-D Tree 中

寻找最优答案时记得剪枝

P5621 [DBOI2019]德丽莎世界第一可爱
(上一题的加权版本,没意思)

P4475 巧克力王国

一样套路记录子树中最大最小的 \(x,y\)

然后判断矩形的四个点是否都符合或都不符合条件,进行剪枝

P4793 [AHOI2008]矩形藏宝地

考虑将第一维从小到大排序,第二维看成权值,三、四维用来建树

每次判断一个点 \(u\) 是否贡献,就是在 K-D Tree 上找到三、四维都大于点 \(u\),而权值小于点 \(u\) 的结点

查询完后再将点 \(u\) 加入到 K-D Tree 中,复杂度就优化到 \(O(n\sqrt n)\)

(不知道为什么,如果按照第四维排序,第三维看成权值,这样会 TLE,看来 K-D Tree 真的能被卡死)

P2093 [国家集训队]JZPFAR
(做法类似 K 远点对)

posted @ 2022-09-28 09:31  zuytong  阅读(74)  评论(0编辑  收藏  举报