From c08289e8bc645db2adf6fd245473c6d2f43c3c0c Mon Sep 17 00:00:00 2001 From: Claudy Forrest <41589268+c-forrest@users.noreply.github.com> Date: Mon, 10 Feb 2025 22:25:42 -0600 Subject: [PATCH] =?UTF-8?q?fix(splay.md):=20=E6=9B=B4=E6=AD=A3=20Splay=20?= =?UTF-8?q?=E6=A0=91=E4=B8=AD=E7=9A=84=E5=A4=8D=E6=9D=82=E5=BA=A6=E8=AF=81?= =?UTF-8?q?=E6=98=8E=20(#6128)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(splay.md): correct complexity analysis --- docs/ds/splay.md | 107 ++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/docs/ds/splay.md b/docs/ds/splay.md index fec91cbbaf98b..76455941d486e 100644 --- a/docs/ds/splay.md +++ b/docs/ds/splay.md @@ -326,101 +326,120 @@ void del(int k) { ## 时间复杂度 -在 Splay 树中,由于 **zig** 和 **zag** 操作是对称的,因此我们只需分析 **zig**、**zig-zig** 和 **zig-zag** 三种操作的复杂度。为此,我们采用 **势能分析法**,通过研究势能的变化来推导操作的均摊复杂度。假设对一棵包含 $n$ 个节点的 Splay 树进行了 $m$ 次 splay 操作,可以通过以下定义和性质来进行分析: +在 Splay 树中,由于 **zig** 和 **zag** 操作是对称的,因此我们只需分析 **zig**、**zig-zig** 和 **zig-zag** 三种操作的复杂度。为此,我们采用 **势能分析法**,通过研究势能的变化来推导操作的均摊复杂度。假设对一棵包含 $n$ 个节点的 Splay 树进行了 $m$ 次 splay 操作,可以通过如下方式进行分析: -**定义**: +**定义**: 1. **单个节点的势能**:$w(x) = \log(\text{size}(x))$,其中 $\text{size}(x)$ 表示以节点 $x$ 为根的子树大小。 -2. **整棵树的势能**:$\varphi = \sum w(x)$,即树中所有节点势能的总和,初始势能满足 $\varphi(0) \leq n \log n$。 +2. **整棵树的势能**:$\varphi = \sum w(x)$,即树中所有节点势能的总和,初始势能满足 $\varphi_0 \leq n \log n$。 -3. **第 $i$ 次操作的均摊成本**:$c_i = t_i + \varphi(i) - \varphi(i-1)$,其中 $t_i$ 为实际操作代价,$\varphi(i)$ 和 $\varphi(i-1)$ 分别为操作后和操作前的势能。 +3. **第 $i$ 次操作的均摊成本**:$c_i = t_i + \varphi_i - \varphi_{i-1}$,其中 $t_i$ 为实际操作代价,$\varphi_i$ 和 $\varphi_{i-1}$ 分别为操作后和操作前的势能。 -**性质**: +**性质**: -1. 如果 $fa$ 是 $x$ 的父节点,则有 $w(fa) \geq w(x)$,即父节点的势能不小于子节点的势能。 +1. 如果 $p$ 是 $x$ 的父节点,则有 $w(p) \geq w(x)$,即父节点的势能不小于子节点的势能。 2. 由于根节点的子树大小在操作前后保持不变,因此根节点的势能在操作过程中不变。 -3. 如果 $fa$ 的两个子节点分别是 $x$ 和 $y$,那么有 $2w(fa) - w(x) - w(y) \geq 2$ +3. 如果 $\text{size}(p)\ge\text{size}(x)+\text{size}(y)$,那么有 $2w(p) - w(x) - w(y) \geq 2$。 ??? note "性质 3 的证明" - 1. 设 $\text{size}(fa) = z$,$\text{size}(x) = y$,$\text{size}(y) = x$,则有 $z = x + y + 1$。 - 2. 因此,$2w(fa) - w(x) - w(y) = \log z^2 - \log y - \log x = \log \frac{z^2}{x \cdot y}$。 - 3. 带入 $z = x + y + 1$,可以推导出:$\log \frac{(x + y + 1)^2}{x \cdot y} > \log \frac{(x + y)^2}{x \cdot y} \geq \log 4 = 2$。 + 根据均值不等式可知 -接下来,分别对 **zig**、**zig-zig** 和 **zig-zag** 操作进行势能分析。 + $$ + \begin{aligned} + 2w(p) - w(x) - w(y) + &= \log\dfrac{\text{size}(p)^2}{\text{size}(x)\cdot\text{size}(y)} \\ + &> \log\dfrac{\left(\text{size}(x)+\text{size}(y)\right)^2}{\text{size}(x)\cdot\text{size}(y)} \\ + &\ge \log 4 \\ + &= 2. + \end{aligned} + $$ -**Zig**:根据性质 1 和 2,有 $w(fa) = w'(x)$,且 $w'(x) \geq w'(fa)$。由此,均摊成本为: +接下来,分别对 **zig**、**zig-zig** 和 **zig-zag** 操作进行势能分析。设操作前后的节点 $x$ 的势能分别是 $w(x)$ 和 $w'(x)$。节点的记号与 [上文](#splay-操作) 一致。 + +**zig**:根据性质 1 和 2,有 $w(p) = w'(x)$,且 $w'(x) \geq w'(p)$。由此,均摊成本为 $$ \begin{aligned} -c_i &= 1 + w'(x) + w'(fa) - w(x) - w(fa)\\ -&= 1 + w'(fa) - w(x)\\ -&\leq 1 + w'(x) - w(x) +c_i &= 1 + w'(x) + w'(p) - w(x) - w(p)\\ +&= 1 + w'(p) - w(x)\\ +&\leq 1 + w'(x) - w(x). \end{aligned} $$ -**Zig-Zig**:根据性质 1 和 2,有 $w(g) = w'(x)$,且 $w'(x) \geq w'(fa)$,并且 $w(x) \leq w(fa)$。根据性质 3,可得: +**zig-zig**:根据性质 1 和 2,有 $w(g) = w'(x)$,且 $w'(x) \geq w'(p)$,$w(x) \leq w(p)$。因为 $$ -2 \cdot w'(x) - w(x) - w'(g) \geq 2 +\begin{aligned} +\text{size}'(x) +&= 3 + \text{size}(A) + \text{size}(B) + \text{size}(C) + \text{size}(D) \\ +&> (1 + \text{size}(A) + \text{size}(B)) + (1 + \text{size}(C) + \text{size}(D)) \\ +&= \text{size}(x) + \text{size}'(g), +\end{aligned} $$ -由此,均摊成本为: +根据性质 3 可得 $$ -c_i = 2 + w'(x) + w'(fa) + w'(g) - w(x) - w(fa) - w(g) +2 w'(x) - w(x) - w'(g) \geq 2. $$ -简化后: +由此,均摊成本为 $$ \begin{aligned} -c_i &= 2 + w'(fa) + w'(g) - w(x) - w(fa)\\ -&\leq 2w'(x) + w'(fa) - 2w(x) - w(fa)\\ -&\leq 3 \cdot (w'(x) - w(x)) +c_i &= 2 + w'(x) + w'(p) + w'(g) - w(x) - w(p) - w(g) \\ +&= 2 + w'(p) + w'(g) - w(x) - w(p) \\ +&\le (2 w'(x) - w(x) - w'(g)) + w'(p) + w'(g) - w(x) - w(p) \\ +&= 2(w'(x)-w(x)) + w'(p) - w(p) \\ +&\le 3(w'(x)-w(x)). \end{aligned} $$ -**Zig-Zag**:根据性质 1 和 2,有 $w(g) = w'(x)$,且 $w(fa) \geq w(x)$。根据性质 3,可得: - -$$ -2 \cdot w'(x) - w'(g) - w'(fa) \geq 2 -$$ - -由此,均摊成本为: +**zig-zag**:根据性质 1 和 2,有 $w(g) = w'(x)$,且 $w(p) \geq w(x)$。因为 $\text{size}'(x)>\text{size}'(p)+\text{size}'(g)$,根据性质 3,可得 $$ -c_i = 2 + w'(x) + w'(fa) + w'(g) - w(x) - w(fa) - w(g) +2 \cdot w'(x) - w'(g) - w'(p) \geq 2. $$ -简化后: +由此,均摊成本为 $$ \begin{aligned} -c_i&= 2 + w'(g) + w'(fa) - w(x) - w(fa)\\ -&\leq 2 \cdot w'(x) - w(x) - w(fa)\\ -&\leq 2 \cdot (w'(x) - w(x)) +c_i &= 2 + w'(x) + w'(p) + w'(g) - w(x) - w(p) - w(g) \\ +&= 2 + w'(p) + w'(g) - w(x) - w(p) \\ +&\le (2w'(x) - w'(g) - w'(p)) + w'(p) + w'(g) - w(x) - w(p) \\ +&= 2w'(x) - w(x) - w(p) \\ +&\le 2(w'(x) - w(x)). \end{aligned} $$ -**总结**: +**单次 Splay 操作**: -由此可见,三种 splay 步骤的均摊成本全部可以缩放为 $\leq 3(w'(x)−w(x))$. 令 $w^{(n)}(x)=w'^{(n-1)}(x)$,$w^{(0)}(x)=w(x)$, 假设一次 splay 操作依次访问了 $x_{1}, x_{2}, \cdots, x_{n}$, 最终 $x_{1}$ 成为根节点,我们可以得到: +令 $w^{(n)}(x)=(w^{(n-1)})'(x)$ 且 $w^{(0)}(x)=w(x)$。假设一次 splay 操作依次访问了 $x_{1}, x_{2}, \cdots, x_{n}$ 等节点,最终 $x_{1}$ 成为根节点。这必然经过若干次 **zig-zig** 和 **zig-zag** 操作和至多一次 **zig** 操作,前两种操作的均摊成本均不超过 $3(w'(x)-w(x))$,而最后一次操作的均摊成本不超过 $3(w'(x) - w(x))+1$,所以总的均摊成本不超过 $$ -\begin{aligned} -3\left(\sum_{i=0}^{n-2}\left(w^{(i+1)}(x_{1})-w^{(i)}(x_{1})\right)+w(n)−w^{(n-1)}(x_{1})\right)+1 & = 3(w(n)−w(x_{1}))+1 \\ -& \leq \log n -\end{aligned} +3(w^{(n)}(x_1) - w^{(0)}(x_1)) + 1 \le 3\log n + 1. $$ -继而可得: +因此,一次 Splay 操作的均摊复杂度是 $O(\log n)$ 的。从而,基于 splay 的插入、查询、删除等操作的时间复杂度也为均摊 $O(\log n)$。 + +??? info " 为什么 Splay 树的再平衡操作可以获得 $O(\log n)$ 的均摊复杂度?" + 朴素的再平衡思路就是对节点反复进行旋转操作使其上升,直到它成为根节点。这种朴素思路的问题在于,对于所有子节点都是左(右)节点的链状树来说,它相当于反复进行 **zig** 操作,因而 **zig** 操作的均摊复杂度中的常数项 $1$ 会不断累积,造成最终的均摊复杂度达到 $O(\log n+n)$ 级别。Splay 树的再平衡操作的设计,避免了连续 **zig** 的情形中的常数累积,使得一次完整的 Splay 操作中,至多进行一次单独的 **zig** 操作,从而优化了时间复杂度。 + +**结论**: + +在进行 $m$ 次 Splay 操作之后,实际成本 $$ -\sum_{i=1}^m (\varphi (m-i+1)−\varphi (m−i)) +\varphi (0) = n \log n+m \log n +\begin{aligned} +\sum_{i=1}^m t_i &= \sum_{i=1}^m \left(c_i + \varphi_{i-1} - \varphi_i \right) \\ +&= \sum_{i=1}^m c_i + \varphi_0 - \varphi_m \\ +&\le m(3\log n+1) + n\log n. +\end{aligned} $$ -因此,对于 $n$ 个节点的 splay 树,做一次 splay 操作的均摊复杂度为 $O(\log n)$。从而基于 splay 的插入,查询,删除等操作的时间复杂度也为均摊 $O(\log n)$。 +因此,$m$ 次 Splay 操作的实际时间复杂度为 $O((m+n)\log n)$。 ## 实现