本部分内容转载并修改自 时间复杂度 - 势能分析浅谈 ,已取得原作者授权同意.
定义
阿克曼函数
这里,先给出 α ( n ) \alpha(n) α ( n ) 的定义.为了给出这个定义,先给出 A k ( j ) A_k(j) A k ( j ) 的定义.
定义 A k ( j ) A_k(j) A k ( j ) 为:
A k ( j ) = { j + 1 k = 0 A k − 1 ( j + 1 ) ( j ) k ≥ 1 A_k(j)=\left\{
\begin{aligned}
&j+1& &k=0&\\
&A_{k-1}^{(j+1)}(j)& &k\geq1&
\end{aligned}
\right. A k ( j ) = { j + 1 A k − 1 ( j + 1 ) ( j ) k = 0 k ≥ 1
即阿克曼函数.
这里,f i ( x ) f^i(x) f i ( x ) 表示将 f f f 连续应用在 x x x 上 i i i 次,即 f 0 ( x ) = x f^0(x)=x f 0 ( x ) = x ,f i ( x ) = f ( f i − 1 ( x ) ) f^i(x)=f(f^{i-1}(x)) f i ( x ) = f ( f i − 1 ( x )) .
再定义 α ( n ) \alpha(n) α ( n ) 为使得 A α ( n ) ( 1 ) ≥ n A_{\alpha(n)}(1)\geq n A α ( n ) ( 1 ) ≥ n 的最小整数值.注意,我们之前将它描述为 A α ( n ) ( α ( n ) ) ≥ n A_{\alpha(n)}(\alpha(n))\geq n A α ( n ) ( α ( n )) ≥ n ,反正他们的增长速度都很慢,值都不超过 4.
基础定义
每个节点都有一个 rank.这里的 rank 不是节点个数,而是深度.节点的初始 rank 为 0,在合并的时候,如果两个节点的 rank 不同,则将 rank 小的节点合并到 rank 大的节点上,并且不更新大节点的 rank 值.否则,随机将某个节点合并到另外一个节点上,将根节点的 rank 值 +1.这里根节点的 rank 给出了该树的高度.记 x 的 rank 为 r n k ( x ) rnk(x) r nk ( x ) ,类似的,记 x 的父节点为 f a ( x ) fa(x) f a ( x ) .我们总有 r n k ( x ) + 1 ≤ r n k ( f a ( x ) ) rnk(x)+1\leq rnk(fa(x)) r nk ( x ) + 1 ≤ r nk ( f a ( x )) .
为了定义势函数,需要预先定义一个辅助函数 l e v e l ( x ) level(x) l e v e l ( x ) .其中,l e v e l ( x ) = max ( k : r n k ( f a ( x ) ) ≥ A k ( r n k ( x ) ) ) level(x)=\max(k:rnk(fa(x))\geq A_k(rnk(x))) l e v e l ( x ) = max ( k : r nk ( f a ( x )) ≥ A k ( r nk ( x ))) .当 r n k ( x ) ≥ 1 rnk(x)\geq1 r nk ( x ) ≥ 1 的时候,再定义一个辅助函数 i t e r ( x ) = max ( i : r n k ( f a ( x ) ) ≥ A l e v e l ( x ) i ( r n k ( x ) ) iter(x)=\max(i:rnk(fa(x))\geq A_{level(x)}^i(rnk(x)) i t er ( x ) = max ( i : r nk ( f a ( x )) ≥ A l e v e l ( x ) i ( r nk ( x )) .这些函数定义的 x x x 都满足 r n k ( x ) > 0 rnk(x)>0 r nk ( x ) > 0 且 x x x 不是某个树的根.
上面那些定义可能让你有点头晕.再理一下,对于一个 x x x 和 f a ( x ) fa(x) f a ( x ) ,如果 r n k ( x ) > 0 rnk(x)>0 r nk ( x ) > 0 ,总是可以找到一对 i , k i,k i , k 令 r n k ( f a ( x ) ) ≥ A k i ( r n k ( x ) ) rnk(fa(x))\geq A_k^i(rnk(x)) r nk ( f a ( x )) ≥ A k i ( r nk ( x )) ,而 l e v e l ( x ) = max ( k ) level(x)=\max(k) l e v e l ( x ) = max ( k ) ,在这个前提下,i t e r ( x ) = max ( i ) iter(x)=\max(i) i t er ( x ) = max ( i ) .l e v e l level l e v e l 描述了 A A A 的最大迭代级数,而 i t e r iter i t er 描述了在最大迭代级数时的最大迭代次数.
对于这两个函数,l e v e l ( x ) level(x) l e v e l ( x ) 总是随着操作的进行而增加或不变,如果 l e v e l ( x ) level(x) l e v e l ( x ) 不增加,i t e r ( x ) iter(x) i t er ( x ) 也只会增加或不变.并且,它们总是满足以下两个不等式:
0 ≤ l e v e l ( x ) < α ( n ) 0\leq level(x)<\alpha(n) 0 ≤ l e v e l ( x ) < α ( n )
1 ≤ i t e r ( x ) ≤ r n k ( x ) 1\leq iter(x)\leq rnk(x) 1 ≤ i t er ( x ) ≤ r nk ( x )
考虑 l e v e l ( x ) level(x) l e v e l ( x ) 、i t e r ( x ) iter(x) i t er ( x ) 和 A k j A_k^j A k j 的定义,这些很容易被证明出来,就留给读者用于熟悉定义了.
定义势能函数 Φ ( S ) = ∑ x ∈ S Φ ( x ) \Phi(S)=\sum\limits_{x\in S}\Phi(x) Φ ( S ) = x ∈ S ∑ Φ ( x ) ,其中 S S S 表示一整个并查集,而 x x x 为并查集中的一个节点.定义 Φ ( x ) \Phi(x) Φ ( x ) 为:
Φ ( x ) = { α ( n ) × r n k ( x ) r n k ( x ) = 0 或 x 为某棵树的根节点 ( α ( n ) − l e v e l ( x ) ) × r n k ( x ) − i t e r ( x ) otherwise \Phi(x)=
\begin{cases}
\alpha(n)\times \mathit{rnk}(x)& \mathit{rnk}(x)=0\ \text{或}\ x\ \text{为某棵树的根节点}\\
(\alpha(n)-\mathit{level}(x))\times \mathit{rnk}(x)-iter(x)& \text{otherwise}
\end{cases} Φ ( x ) = { α ( n ) × rnk ( x ) ( α ( n ) − level ( x )) × rnk ( x ) − i t er ( x ) rnk ( x ) = 0 或 x 为某棵树的根节点 otherwise
然后就是通过操作引起的势能变化来证明摊还时间复杂度为 Θ ( α ( n ) ) \Theta(\alpha(n)) Θ ( α ( n )) 啦.注意,这里我们讨论的 u n i o n ( x , y ) union(x,y) u ni o n ( x , y ) 操作保证了 x x x 和 y y y 都是某个树的根,因此不需要额外执行 f i n d ( x ) find(x) f in d ( x ) 和 f i n d ( y ) find(y) f in d ( y ) .
可以发现,势能总是个非负数.另,在开始的时候,并查集的势能为 0 0 0 .
证明
union(x,y) 操作
其花费的时间为 Θ ( 1 ) \Theta(1) Θ ( 1 ) ,因此我们考虑其引起的势能的变化.
这里,我们假设 r n k ( x ) ≤ r n k ( y ) rnk(x)\leq rnk(y) r nk ( x ) ≤ r nk ( y ) ,即 x x x 被接到 y y y 上.这样,势能增加的节点仅有 x x x (从树根变成非树根),y y y (秩可能增加)和操作前 y y y 的子节点(父节点的秩可能增加).我们先证明操作前 y y y 的子节点 c c c 的势能不可能增加,并且如果减少了,至少减少 1 1 1 .
设操作前 c c c 的势能为 Φ ( c ) \Phi(c) Φ ( c ) ,操作后为 Φ ( c ′ ) \Phi(c') Φ ( c ′ ) ,这里 c c c 可以是任意一个 r n k ( c ) > 0 rnk(c)>0 r nk ( c ) > 0 的非根节点,操作可以是任意操作,包括下面的 find 操作.我们分三种情况讨论.
i t e r ( c ) iter(c) i t er ( c ) 和 l e v e l ( c ) level(c) l e v e l ( c ) 并未增加.显然有 Φ ( c ) = Φ ( c ′ ) \Phi(c)=\Phi(c') Φ ( c ) = Φ ( c ′ ) .
i t e r ( c ) iter(c) i t er ( c ) 增加了,l e v e l ( c ) level(c) l e v e l ( c ) 并未增加.这里 i t e r ( c ) iter(c) i t er ( c ) 至少增加一,即 Φ ( c ′ ) ≤ Φ ( c ) − 1 \Phi(c')\leq \Phi(c)-1 Φ ( c ′ ) ≤ Φ ( c ) − 1 ,势能函数减少了,并且至少减少 1.
l e v e l ( c ) level(c) l e v e l ( c ) 增加了,i t e r ( c ) iter(c) i t er ( c ) 可能减少.但是由于 0 < i t e r ( c ) ≤ r n k ( c ) 0<iter(c)\leq rnk(c) 0 < i t er ( c ) ≤ r nk ( c ) ,i t e r ( c ) iter(c) i t er ( c ) 最多减少 r n k ( c ) − 1 rnk(c)-1 r nk ( c ) − 1 ,而 l e v e l ( c ) level(c) l e v e l ( c ) 至少增加 1 1 1 .由定义 Φ ( c ) = ( α ( n ) − l e v e l ( c ) ) × r n k ( c ) − i t e r ( c ) \Phi(c)=(\alpha(n)-level(c))\times rnk(c)-iter(c) Φ ( c ) = ( α ( n ) − l e v e l ( c )) × r nk ( c ) − i t er ( c ) ,可得 Φ ( c ′ ) ≤ Φ ( c ) − 1 \Phi(c')\leq\Phi(c)-1 Φ ( c ′ ) ≤ Φ ( c ) − 1 .
其他情况.由于 r n k ( c ) rnk(c) r nk ( c ) 不变,r n k ( f a ( c ) ) rnk(fa(c)) r nk ( f a ( c )) 不减,所以不存在.
所以,势能增加的节点仅可能是 x x x 或 y y y .而 x x x 从树根变成了非树根,如果 r n k ( x ) = 0 rnk(x)=0 r nk ( x ) = 0 ,则一直有 Φ ( x ) = Φ ( x ′ ) = 0 \Phi(x)=\Phi(x')=0 Φ ( x ) = Φ ( x ′ ) = 0 .否则,一定有 α ( x ) × r n k ( x ) ≥ ( α ( n ) − l e v e l ( x ) ) × r n k ( x ) − i t e r ( x ) \alpha(x)\times rnk(x)\geq(\alpha(n)-level(x))\times rnk(x)-iter(x) α ( x ) × r nk ( x ) ≥ ( α ( n ) − l e v e l ( x )) × r nk ( x ) − i t er ( x ) .即,Φ ( x ′ ) ≤ Φ ( x ) \Phi(x')\leq \Phi(x) Φ ( x ′ ) ≤ Φ ( x ) .
因此,唯一势能可能增加的点就是 y y y .而 y y y 的势能最多增加 α ( n ) \alpha(n) α ( n ) .因此,可得 u n i o n union u ni o n 操作均摊后的时间复杂度为 Θ ( α ( n ) ) \Theta(\alpha(n)) Θ ( α ( n )) .
find(a) 操作
如果查找路径包含 Θ ( s ) \Theta(s) Θ ( s ) 个节点,显然其查找的时间复杂度是 Θ ( s ) \Theta(s) Θ ( s ) .如果由于查找操作,没有节点的势能增加,且至少有 s − α ( n ) s-\alpha(n) s − α ( n ) 个节点的势能至少减少 1 1 1 ,就可以证明 f i n d ( a ) find(a) f in d ( a ) 操作的时间复杂度为 Θ ( α ( n ) ) \Theta(\alpha(n)) Θ ( α ( n )) .为了避免混淆,这里用 a a a 作为参数,而出现的 x x x 都是泛指某一个并查集内的结点.
首先证明没有节点的势能增加.很显然,我们在上面证明过所有非根节点的势能不增,而根节点的 r n k rnk r nk 没有改变,所以没有节点的势能增加.
接下来证明至少有 s − α ( n ) s-\alpha(n) s − α ( n ) 个节点的势能至少减少 1 1 1 .我们上面证明过了,如果 l e v e l ( x ) level(x) l e v e l ( x ) 或者 i t e r ( x ) iter(x) i t er ( x ) 有改变的话,它们的势能至少减少 1 1 1 .所以,只需要证明至少有 s − α ( n ) s-\alpha(n) s − α ( n ) 个节点的 l e v e l ( x ) level(x) l e v e l ( x ) 或者 i t e r ( x ) iter(x) i t er ( x ) 有改变即可.
回忆一下非根节点势能的定义,Φ ( x ) = ( α ( n ) − l e v e l ( x ) ) × r n k ( x ) − i t e r ( x ) \Phi(x)=(\alpha(n)-level(x))\times rnk(x)-iter(x) Φ ( x ) = ( α ( n ) − l e v e l ( x )) × r nk ( x ) − i t er ( x ) ,而 l e v e l ( x ) level(x) l e v e l ( x ) 和 i t e r ( x ) iter(x) i t er ( x ) 是使 r n k ( f a ( x ) ) ≥ A l e v e l ( x ) i t e r ( x ) ( r n k ( x ) ) rnk(fa(x))\geq A_{level(x)}^{iter(x)}(rnk(x)) r nk ( f a ( x )) ≥ A l e v e l ( x ) i t er ( x ) ( r nk ( x )) 的最大数.
所以,如果 r o o t x root_x r oo t x 代表 x x x 所处的树的根节点,只需要证明 r n k ( r o o t x ) ≥ A l e v e l ( x ) i t e r ( x ) + 1 ( r n k ( x ) ) rnk(root_x)\geq A_{level(x)}^{iter(x)+1}(rnk(x)) r nk ( r oo t x ) ≥ A l e v e l ( x ) i t er ( x ) + 1 ( r nk ( x )) 就好了.根据 A k i A_k^i A k i 的定义,A l e v e l ( x ) i t e r ( x ) + 1 ( r n k ( x ) ) = A l e v e l ( x ) ( A l e v e l ( x ) i t e r ( x ) ( r n k ( x ) ) ) A_{level(x)}^{iter(x)+1}(rnk(x))=A_{level(x)}(A_{level(x)}^{iter(x)}(rnk(x))) A l e v e l ( x ) i t er ( x ) + 1 ( r nk ( x )) = A l e v e l ( x ) ( A l e v e l ( x ) i t er ( x ) ( r nk ( x ))) .
注意,我们可能会用 k ( x ) k(x) k ( x ) 代表 l e v e l ( x ) level(x) l e v e l ( x ) ,i ( x ) i(x) i ( x ) 代表 i t e r ( x ) iter(x) i t er ( x ) 以避免式子过于冗长.这里,就是 r n k ( r o o t x ) ≥ A k ( x ) ( A k ( x ) i ( x ) ( x ) ) rnk(root_x)\geq A_{k(x)}(A_{k(x)}^{i(x)}(x)) r nk ( r oo t x ) ≥ A k ( x ) ( A k ( x ) i ( x ) ( x )) .
当你看到这的时候,可能会有一种「这啥玩意」的感觉.这意味着你可能需要多看几遍,或者跳过一些内容以后再看.
这里,我们需要一个外接的 A k ( x ) A_{k(x)} A k ( x ) ,意味着我们可能需要再找一个点 y y y .令 y y y 是搜索路径上在 x x x 之后的满足 k ( y ) = k ( x ) k(y)=k(x) k ( y ) = k ( x ) 的点,这里「搜索路径之后」相当于「是 x x x 的祖先」.显然,不是每一个 x x x 都有这样一个 y y y .很容易证明,没有这样的 y y y 的 x x x 不超过 α ( n ) + 2 \alpha(n)+2 α ( n ) + 2 个.因为只有每个 k k k 的最后一个 x x x 和 a a a 以及 r o o t a root_a r oo t a 没有这样的 y y y .
我们再强调一遍 f a ( x ) fa(x) f a ( x ) 指的是路径压缩 之前 x x x 的父节点,路径压缩 之后 x x x 的父节点一律用 r o o t x root_x r oo t x 表示.对于每个存在 y y y 的 x x x ,总是有 r n k ( y ) ≥ r n k ( f a ( x ) ) rnk(y)\geq rnk(fa(x)) r nk ( y ) ≥ r nk ( f a ( x )) .同时,我们有 r n k ( f a ( x ) ) ≥ A k ( x ) i ( x ) ( r n k ( x ) ) rnk(fa(x))\geq A_{k(x)}^{i(x)}(rnk(x)) r nk ( f a ( x )) ≥ A k ( x ) i ( x ) ( r nk ( x )) .由于 k ( x ) = k ( y ) k(x)=k(y) k ( x ) = k ( y ) ,我们用 k k k 来统称,即,r n k ( f a ( x ) ) ≥ A k i ( x ) ( r n k ( x ) ) rnk(fa(x))\geq A_k^{i(x)}(rnk(x)) r nk ( f a ( x )) ≥ A k i ( x ) ( r nk ( x )) .我们需要造一个 A k A_k A k 出来,所以我们可以不关注 i t e r ( y ) iter(y) i t er ( y ) 的值,直接使用弱化版的 r n k ( f a ( y ) ) ≥ A k ( r n k ( y ) ) rnk(fa(y))\geq A_k(rnk(y)) r nk ( f a ( y )) ≥ A k ( r nk ( y )) .
如果我们将不等式组合起来,神奇的事情就发生了.我们发现,r n k ( f a ( y ) ) ≥ A k i ( x ) + 1 ( r n k ( x ) ) rnk(fa(y))\geq A_k^{i(x)+1}(rnk(x)) r nk ( f a ( y )) ≥ A k i ( x ) + 1 ( r nk ( x )) .也就是说,为了从 r n k ( x ) rnk(x) r nk ( x ) 迭代到 r n k ( f a ( y ) ) rnk(fa(y)) r nk ( f a ( y )) ,至少可以迭代 A k A_k A k 不少于 i ( x ) + 1 i(x)+1 i ( x ) + 1 次而不超过 r n k ( f a ( y ) ) rnk(fa(y)) r nk ( f a ( y )) .
显然,有 r n k ( r o o t y ) ≥ r n k ( f a ( y ) ) rnk(root_y)\geq rnk(fa(y)) r nk ( r oo t y ) ≥ r nk ( f a ( y )) ,且 r n k ( x ) rnk(x) r nk ( x ) 在路径压缩时不变.因此,我们可以得到 r n k ( r o o t x ) ≥ A k i ( x ) + 1 ( r n k ( x ) ) rnk(root_x)\geq A_k^{i(x)+1}(rnk(x)) r nk ( r oo t x ) ≥ A k i ( x ) + 1 ( r nk ( x )) ,也就是说 i t e r ( x ) iter(x) i t er ( x ) 的值至少增加 1,如果 r n k ( x ) rnk(x) r nk ( x ) 没有增加,一定是 l e v e l ( x ) level(x) l e v e l ( x ) 增加了.
所以,Φ ( x ) \Phi(x) Φ ( x ) 至少减少了 1.由于这样的 x x x 节点至少有 s − α ( n ) − 2 s-\alpha(n)-2 s − α ( n ) − 2 个,所以最后 Φ ( S ) \Phi(S) Φ ( S ) 至少减少了 s − α ( n ) − 2 s-\alpha(n)-2 s − α ( n ) − 2 ,均摊后的时间复杂度即为 Θ ( α ( n ) + 2 ) = Θ ( α ( n ) ) \Theta(\alpha(n)+2)=\Theta(\alpha(n)) Θ ( α ( n ) + 2 ) = Θ ( α ( n )) .
为何并查集会被卡
这个问题也就是问,如果我们不按秩合并,会有哪些性质被破坏,导致并查集的时间复杂度不能保证为 Θ ( m α ( n ) ) \Theta(m\alpha(n)) Θ ( m α ( n )) .
如果我们在合并的时候,r n k rnk r nk 较大的合并到了 r n k rnk r nk 较小的节点上面,我们就将那个 r n k rnk r nk 较小的节点的 r n k rnk r nk 值设为另一个节点的 r n k rnk r nk 值加一.这样,我们就能保证 r n k ( f a ( x ) ) ≥ r n k ( x ) + 1 rnk(fa(x))\geq rnk(x)+1 r nk ( f a ( x )) ≥ r nk ( x ) + 1 ,从而不会出现类似于满地 compile error 一样的性质不符合.
显然,如果这样子的话,我们破坏的就是 u n i o n ( x , y ) union(x,y) u ni o n ( x , y ) 函数「y 的势能最多增加 α ( n ) \alpha(n) α ( n ) 」这一句.
存在一个能使路径压缩并查集时间复杂度降至 Ω ( m log 1 + m n n ) \Omega(m\log_{1+\frac{m}{n}}n) Ω ( m log 1 + n m n ) 的结构,定义如下:
二项树(实际上和一般的二项树不太一样),其中 j 是常数,T k T_k T k 为一个 T k − 1 T_{k-1} T k − 1 加上一个 T k − j T_{k-j} T k − j 作为根节点的儿子.
二项树
边界条件,T 1 T_1 T 1 到 T j T_j T j 都是一个单独的点.
令 r n k ( T k ) = r k rnk(T_k)=r_k r nk ( T k ) = r k ,这里我们有 r k = ( k − 1 ) / j r_k=(k-1)/j r k = ( k − 1 ) / j (证明略).每轮操作,我们将它接到一个单节点上,然后查询底部的 j j j 个节点.也就是说,我们接到单节点上的时候,单节点的势能提高了 ( k − 1 ) / j + 1 (k-1)/j+1 ( k − 1 ) / j + 1 .在 j = ⌊ m n ⌋ j=\lfloor\frac{m}{n}\rfloor j = ⌊ n m ⌋ ,i = ⌊ log j + 1 n 2 ⌋ i=\lfloor\log_{j+1}\frac{n}{2}\rfloor i = ⌊ log j + 1 2 n ⌋ ,k = i j k=ij k = ij 的时候,势能增加量为:
α ( n ) × ( ( i j − 1 ) / j + 1 ) = α ( n ) × ( ( ⌊ log ⌊ m n ⌋ + 1 n 2 ⌋ × ⌊ m n ⌋ − 1 ) / ⌊ m n ⌋ + 1 ) \alpha(n)\times((ij-1)/j+1)=\alpha(n)\times((\lfloor\log_{\lfloor\frac{m}{n}\rfloor+1}\frac{n}{2}\rfloor\times \lfloor\frac{m}{n}\rfloor-1)/\lfloor\frac{m}{n}\rfloor+1) α ( n ) × (( ij − 1 ) / j + 1 ) = α ( n ) × ((⌊ log ⌊ n m ⌋ + 1 2 n ⌋ × ⌊ n m ⌋ − 1 ) / ⌊ n m ⌋ + 1 )
变换一下,去掉所有的取整符号,就可以得出,势能增加量 ≥ α ( n ) × ( log 1 + m n n − n m ) \geq \alpha(n)\times(\log_{1+\frac{m}{n}}n-\frac{n}{m}) ≥ α ( n ) × ( log 1 + n m n − m n ) ,m 次操作就是 Ω ( m log 1 + m n n − n ) = Ω ( m log 1 + m n n ) \Omega(m\log_{1+\frac{m}{n}}n-n)=\Omega(m\log_{1+\frac{m}{n}}n) Ω ( m log 1 + n m n − n ) = Ω ( m log 1 + n m n ) .
关于启发式合并
由于按秩合并比启发式合并难写,所以很多 dalao 会选择使用启发式合并来写并查集.具体来说,则是对每个根都维护一个 s i z e ( x ) size(x) s i z e ( x ) ,每次将 s i z e size s i z e 小的合并到大的上面.
所以,启发式合并会不会被卡?
首先,可以从秩参与证明的性质来说明.如果 s i z e size s i z e 可以代替 r n k rnk r nk 的地位,则可以使用启发式合并.快速总结一下,秩参与证明的性质有以下三条:
每次合并,最多有一个节点的秩上升,而且最多上升 1.
总有 r n k ( f a ( x ) ) ≥ r n k ( x ) + 1 rnk(fa(x))\geq rnk(x)+1 r nk ( f a ( x )) ≥ r nk ( x ) + 1 .
节点的秩不减.
关于第二条和第三条,s i z siz s i z 显然满足,然而第一条不满足,如果将 x x x 合并到 y y y 上面,则 s i z ( y ) siz(y) s i z ( y ) 会增大 s i z ( x ) siz(x) s i z ( x ) 那么多.
所以,可以考虑使用 log 2 s i z ( x ) \log_2 siz(x) log 2 s i z ( x ) 代替 r n k ( x ) rnk(x) r nk ( x ) .
关于第一条性质,由于节点的 s i z siz s i z 最多翻倍,所以 log 2 s i z ( x ) \log_2 siz(x) log 2 s i z ( x ) 最多上升 1.关于第二三条性质,结论较为显然,这里略去证明.
所以说,如果不想写按秩合并,就写启发式合并好了,时间复杂度仍旧是 Θ ( m α ( n ) ) \Theta(m\alpha(n)) Θ ( m α ( n )) .