概述
就是一直很不理解的, k-d tree \text{k-d tree} k-d tree 的区间查询的复杂度。
算法流程
- 查询一个矩形区域,如果与当前区域无交集,立刻 r e t u r n \tt return return 。
- 如果当前区域被完全包含,立刻 r e t u r n \tt return return 。
- 否则往左右子树分别递归。记此类点的数量为 γ \gamma γ 。
时间复杂度
r e t u r n \tt return return 了的节点,都存在一个没有 r e t u r n \tt return return 的父节点,所以数量不超过 2 γ 2\gamma 2γ 。设 访问一个节点的复杂度是 O ( 1 ) \mathcal O(1) O(1),则查询复杂度是 O ( γ ) \mathcal O(\gamma) O(γ) 。问题在于求出 γ \gamma γ 。
k-d tree \text{k-d tree} k-d tree 是仿照线段树而诞生的(我猜的),所以也要仿照线段树的复杂度证明。即,如果往左右子树分别递归,那么一定是 划分线(当前点对应的那条分割线)跨过了查询区间。这会导致子节点的查询区间都 紧贴边缘(查询区间紧贴划分线,划分线就是子节点的边缘)。
对于某一维,用 0 , 1 , 2 0,1,2 0,1,2 表示查询区间紧贴着多少个边缘。那么划分线把它 “切开” 就会导致 0 → 1 , 1 0\to 1,1 0→1,1 或 1 → 1 , 2 1\to 1,2 1→1,2 或 2 → 2 , 2 2\to 2,2 2→2,2 。而每一维都是 2 2 2,就是被完全包含,此时会 r e t u r n \tt return return,不能统计。
最初,每一维都是 0 0 0 。若不 “切开”,则下一层点数不变,而 “切开” 可以使得点数翻倍。贪心地想,最坏情况肯定是直接把 0 0 0 都 “切开” 成 1 , 1 1,1 1,1 。于是,过了 k k k 层,我们就获得了 2 k 2^k 2k 个每一维都是 1 1 1 的状态。
接下来就只有 1 → 1 , 2 1\to 1,2 1→1,2 和 2 → 2 , 2 2\to 2,2 2→2,2 两种转移。它可以看成有向图的行走(矩阵乘法)。那么,假如有 x x x 轮 移动,即 x k xk xk 层,那么枚举 1 1 1 第一次走到 2 2 2 的时间 t t t,则该维上的行走情况数是 ∑ t = 0 x 2 x − t = 2 x + 1 − 1 \sum_{t=0}^x2^{x-t}=2^{x+1}-1 ∑t=0x2x−t=2x+1−1 。每一维都走到 2 2 2 是不合法的(不在 γ \gamma γ 统计范畴内),于是枚举一个维度没走到 2 2 2,剩下的维度都乱走,则总情况数有上界 k ⋅ ( 2 x + 1 − 1 ) k − 1 k\cdot (2^{x+1}{\rm-}1)^{k-1} k⋅(2x+1−1)k−1 。为何是上界?因为有很多种情况算重了。
层数共
log
n
\log n
logn,再减去最初用于 “切开” 的
k
k
k 层,轮数
x
=
log
n
−
k
k
x=\frac{\log n-k}{k}
x=klogn−k 。代入上式得
k
(
n
k
−
1
)
k
−
1
k\left(\sqrt[k]{n}-1\right)^{k-1}
k(kn−1)k−1
其实这只是最底层的 γ \gamma γ 点数量。但是 ( 2 x + 1 ) k − 1 (2^{x+1})^{k-1} (2x+1)k−1 是指数级增长,较小的 x x x 一定得到高阶无穷小,所以在下面的 big- O \text{big-}\mathcal O big-O 中可以忽略。——线段树则是 k = 1 k=1 k=1 的特例,此时它不是指数级增长,必须求和,所以是 O ( log n ) \mathcal O(\log n) O(logn) 。
最后乘上起点的系数
2
k
2^k
2k,用
O
\mathcal O
O 做简化得
O
(
2
k
k
n
1
−
1
k
)
\mathcal O(2^kkn^{1-{1\over k}})
O(2kkn1−k1)
我感觉复杂度就是这个。而有人似乎能证明是 O ( k n 1 − 1 k ) \mathcal O(kn^{1-{1\over k}}) O(kn1−k1) 的,对此我只能表示: O ( k n 1 − 1 k ) ⫅ O ( 2 k k n 1 − 1 k ) \mathcal O(kn^{1-{1\over k}})\subseteqq\mathcal O(2^kkn^{1-{1\over k}}) O(kn1−k1)⫅O(2kkn1−k1),所以我也没错(手动滑稽)。