[后缀自动机]SAM的一点理解

主要参考资料:CLJppt。

预备知识

自动机组成:状态、初始状态、终止状态、状态转移、字符集。

什么是状态?

经典图片:

ACADD对应的SAM


对于整个串而言,初始状态(以下简称为init)为ROOT,终止状态集合(以下简称end)为最上方及最右方的那两个写着D的(状态既不是字符,也不是子串,在这里把它理解为某个下标更好),所有的状态就是那七个圈,每条实线边代表从一个状态向另一个状态的状态转移。字符集不太重要,在这里为26个字母(暂不区分大小写)。

定义的标注

为便于阅读及写作,下文中,定义均使用

  • 定义

的格式进行标注。当发现有问题时,不妨回到开头再看一眼定义

正文

Part 1 自动机&&后缀自动机的一些定义

  • t r a n s ( ) trans() trans()代表状态转移函数(即上文所说边)。
  • t r a n s ( s , c h ) trans(s,ch) trans(s,ch)表示从状态s起,通过字符ch转移所到达的状态(就是走标号为ch的边到达的点)。
  • t r a n s ( s , c h ) trans(s,ch) trans(s,ch)表示的状态若不存在,则值为NULL。同时规定 t r a n s ( N U L L , a n y p o s s i b l e v a l u e ) trans(NULL,any_possible_value) trans(NULL,anypossiblevalue)只能为NULL。

例如,上图中,如果当前状态在左下角的A这个,通过’D’可以转移到右下角倒数第二个D这个,通过’C’可以转移到。。。唯一的C所在的

由于一直用**圈**表述状态实在太麻烦,因此在不引起歧义的前提下,我也会使用某个字符来表示状态。但请时刻注意,状态并非字符。

  • t r a n s ( s , s t r ) trans(s,str) trans(s,str)表示从s状态起,通过字符串str转移后到达的状态。

例如,上图中,从init通过字符串"AC"转移可以到达唯一的那个C。

很明显,有如下函数(伪代码):

trans(s,str)
    cur = s;
    for i = 0 to len(str) - 1
        cur = trans(cur, str[i])
    return cur

就是说, t r a n s ( s , s t r ) trans(s,str) trans(s,str)可以看成是一大堆 t r a n s ( s , c h ) trans(s,ch) trans(s,ch)的总和。

  • 于是某个自动机A能识别的字符串就是所有使得 t r a n s ( i n i t , x ) ∈ e n d trans(init,x) \in end trans(init,x)end的字符串x。记为 R e g ( A ) Reg(A) Reg(A)

(说白了就是把x放到ROOT上开始沿着边跑,如果在end中节点上结束,就说能识别。栗子:我往一颗Trie树中插了字符串"ACADD",那这颗Trie就能识别"ACADD",不能识别"ACA"、"BC"等等奇奇怪怪的字符串)

  • 从状态s开始能识别的字符串,就是所有使得 t r a n s ( i n i t , x ) ∈ e n d trans(init,x) \in end trans(init,x)end的字符串,记为 R e g ( s ) Reg(s) Reg(s)
  • R e g ( ) Reg() Reg()的值是个集合。

比如,还是刚才那图,从C开始,"DD"可以被识别(因为 t r a n s ( C trans(C trans(C所在的 " D D " ) ∈ e n d "DD") \in end "DD")end

  • S的后缀自动机(以下简称为SAM),能够识别S的所有后缀。

也就是说,当且仅当x是S的后缀时, x ∈ R e g ( S A M ) x \in Reg(SAM) xReg(SAM)。既然能识别所有的后缀,那我们扩展end集合后,SAM也能识别S所有后缀的前缀,即S的子串。

Part 2 减少状态及一些性质

当然我们可以把一个串的所有后缀都插入Trie树,这当然也是后缀自动机,但是时间、空间复杂度都是 O ( n 2 ) O(n^2) O(n2)

考虑到这样一颗Trie树会有很多重复的字符,因此我们需要最简状态后缀自动机,即状态数(就是需要的圈)最少的后缀自动机。

一些性质

  • S T ( s t r ) = t r a n s ( i n i t , s t r ) ST(str)=trans(init,str) ST(str)=trans(init,str)

定义 S T ( s t r ) ST(str) ST(str)为初始状态读入str(以下用“读入%s”表示“通过%s转移”)后到达的状态。

  • S u f Suf Suf:原串S后缀的集合
  • F a c Fac Fac:原串S子串的集合
  • S [ l , r ) S[l,r) S[l,r)表示S中 [ l , r ) [l,r) [l,r)这个区间构成的子串。
  • S u f f i x ( a ) Suffix(a) Suffix(a)表示从位置a开始的后缀,即 S [ a , l e n ( s ) ) S[a,len(s)) S[a,len(s))
  • 约定S下标从0开始。
  • l > = r l>=r l>=r S [ l , r ) = " " S[l,r)="" S[l,r)=""

对于一个字符串s,如果 s ∉ F a c s \notin Fac s/Fac,那么 S T ( s ) = N U L L ST(s)=NULL ST(s)=NULL(显然)。而如果 s ∈ F a c s \in Fac sFac,那么 S T ( S ) ̸ = N U L L ST(S) \not= NULL ST(S)̸=NULL,因为如果s是S的子串,在s后面加上一些字符就可能变为S的后缀。

考虑朴素的插入,是对每个 s ∈ F a c s \in Fac sFac新建一个状态(既然对所有后缀建一条链,那对于某个后缀的前缀的最后一个字符,都要新建一个状态,那么可以看作对每个子串新建了一个状态),这样做是 O ( n 2 ) O(n^2) O(n2)的。

考虑对于某个字符串 a a a S T ( a ) ST(a) ST(a)能识别那些字符串,即从 S T ( a ) ST(a) ST(a)起通过那些字符串可转移到end,即 R e g ( S T ( a ) ) Reg(ST(a)) Reg(ST(a))

x ∈ R e g ( S A M ) x \in Reg(SAM) xReg(SAM),当且仅当 x ∈ S u f x \in Suf xSuf

x ∈ R e g ( S T ( a ) ) x \in Reg(ST(a)) xReg(ST(a)),当且仅当 a x ∈ S u f ax \in Suf axSuf

也就是说ax是S后缀,那么x必定也是S后缀。 ∴ R e g ( S T ( a ) ) \therefore Reg(ST(a)) Reg(ST(a))是一些后缀集合。

现在,对于一个状态s,我们只关注 R e g ( s ) Reg(s) Reg(s)

对于某个子串a,如果 S [ l , r ) = = a S[l,r)==a S[l,r)==a,那么 S T ( a ) ST(a) ST(a)能识别 S u f f i x ( r ) Suffix(r) Suffix(r)

如果a在S中出现的位置的集合为 { ( l , r ) ∣ S [ l , r ) = = a } = { [ l 1 , r 1 ) , [ l 2 , r 2 ) , . . . , [ l n , r n ) } \{(l,r)|S[l,r)==a\}=\{[l_1,r_1),[l_2,r_2),...,[l_n,r_n)\} {(l,r)S[l,r)==a}={[l1,r1),[l2,r2),...,[ln,rn)},那么 R e g ( S T ( a ) ) = { S u f f i x ( r 1 ) , S u f f i x ( r 2 ) , . . . , S u f f i x ( r n ) } Reg(ST(a))=\{Suffix(r_1),Suffix(r_2),...,Suffix(r_n)\} Reg(ST(a))={Suffix(r1),Suffix(r2),...,Suffix(rn)}

不妨令 R i g h t ( a ) = { r 1 , r 2 , . . . , r n } Right(a)=\{r_1,r_2,...,r_n\} Right(a)={r1,r2,...,rn}

那么 R e g ( S T ( a ) ) Reg(ST(a)) Reg(ST(a))完全由 R i g h t ( a ) Right(a) Right(a)决定。

又因为我们要使状态数最少,那所有状态s应该与所有 R e g ( s ) Reg(s) Reg(s)一一对应(首先,每个状态s一定能映射到一个Reg集合。然后,如果两个s映射到同一个Reg集合,为什么不把它们合并呢?)。也就是说, R e g ( S T ( a ) ) = = R e g ( S T ( b ) ) ⇔ S T ( a ) = = S T ( b ) Reg(ST(a))==Reg(ST(b)) \Leftrightarrow ST(a)==ST(b) Reg(ST(a))==Reg(ST(b))ST(a)==ST(b)

那么对于两个子串 a , b ∈ F a c a,b \in Fac a,bFac,如果 R i g h t ( a ) = R i g h t ( b ) Right(a)=Right(b) Right(a)=Right(b),那么 R e g ( S T ( a ) ) = R e g ( S T ( b ) ) Reg(ST(a))=Reg(ST(b)) Reg(ST(a))=Reg(ST(b)),即 S T ( a ) = S T ( b ) ST(a)=ST(b) ST(a)=ST(b)

  • R i g h t ( S T ( a ) ) = R i g h t ( a ) Right(ST(a))=Right(a) Right(ST(a))=Right(a)

所以一个状态s,可以由所有 R i g h t Right Right集合是 R i g h t ( s ) Right(s) Right(s)的字符串从init转移到达。记这些字符串为 S u b ( s ) Sub(s) Sub(s)

  • S u b ( s ) = { s t r ∣ S T ( s t r ) = s } Sub(s)=\{str|ST(str)=s\} Sub(s)={strST(str)=s}

不妨设 r ∈ R i g h t ( s ) r \in Right(s) rRight(s),那么如果再给出一个合法的子串长度len,那么这个子串就是 S [ r − l e n , r ) S[r-len,r) S[rlen,r)。即给定某个合法的(在这里指存在某个状态s的Right集合等于它)Right集合后,再给出一个合法的长度就可以确定子串了。

考虑对于一个Right集合,如果对于串长为 l e n = l   o r   l e n = r len=l\ or\ len=r len=l or len=r的子串是合法的,那么对于 l e n ∈ [ l , r ] len \in [l,r] len[l,r]的子串也一定合法。

一些说明:设Right集合 R 1 R_1 R1中有一元素 s u b s t r i n g _ r 1 substring\_r_1 substring_r1,在 l e n = l   o r   l e n = r ( l &lt; = r ) len=l\ or\ len=r(l&lt;=r) len=l or len=r(l<=r)的情况下 R i g h t ( S [ s u b s t r i n g _ r 1 − l e n , s u b s t r i n g _ r 1 ) ) = R 1 Right(S[substring\_r_1-len,substring\_r_1))=R_1 Right(S[substring_r1len,substring_r1))=R1,那么情况如图。

很显然,对于 l e n ∈ [ l , r ] , S [ s u b s t r i n g _ r 1 − l e n , s u b s t r i n g _ r 1 ) len \in [l,r],S[substring\_r_1-len,substring\_r_1) len[l,r],S[substring_r1len,substring_r1),都可以且仅可以识别R1中元素开始的后缀。而对于 l e n &gt; r len&gt;r len>r,只能保证仅可以;对于 l e n &lt; l len&lt;l len<l,只能保证可以。因此在 l e n ∉ [ l , r ] len \notin [l,r] len/[l,r]情况下,不保证 R i g h t ( S [ s u b s t r i n g _ r 1 − l e n , s u b s t r i n g _ r 1 ) ) = R 1 Right(S[substring\_r_1-len,substring\_r_1))=R_1 Right(S[substring_r1len,substring_r1))=R1

所以对于一个Right集,合法的长度只能存在于一个区间内。

不妨设对于一状态s,合法的区间长度为 [ M i n ( s ) , M a x ( s ) ] [Min(s),Max(s)] [Min(s),Max(s)]

状态数线性证明

考虑两个状态a,b,各自的Right集合分别为 R a , R b R_a,R_b Ra,Rb

假设 R a ∩ R b ̸ = ∅ R_a \cap R_b \not= \emptyset RaRb̸=,设 r ∈ R a ∩ R b r \in R_a \cap R_b rRaRb

由于 S u b ( a ) , S u b ( b ) Sub(a),Sub(b) Sub(a),Sub(b)不会有交集( t r a n s ( i n i t , s t r ) trans(init,str) trans(init,str)只能到达一个状态),所以 [ M i n ( a ) , M a x ( a ) ] [Min(a),Max(a)] [Min(a),Max(a)] [ M i n ( b ) , M a x ( b ) ] [Min(b),Max(b)] [Min(b),Max(b)]也不可能有交集(不然的话以r为结束的某些子串会既到达a,又到达b)。

不妨设 M a x ( a ) &lt; M i n ( b ) Max(a)&lt;Min(b) Max(a)<Min(b),那么 S u b ( a ) Sub(a) Sub(a)中所有串长度都小于 S u b ( b ) Sub(b) Sub(b)中的串。由于 S u b ( a ) , S u b ( b ) Sub(a),Sub(b) Sub(a),Sub(b)中的串都可以接上 S u f f i x ( r ) Suffix(r) Suffix(r) R i g h t Right Right定义),那么 S u b ( a ) Sub(a) Sub(a)中串必定是 S u b ( b ) Sub(b) Sub(b)中串的后缀。

于是 S u b ( b ) Sub(b) Sub(b)中某串出现的位置上, S u b ( a ) Sub(a) Sub(a)中某串也必然能在这里出现。因此 R b ⊂ R a R_b \subset R_a RbRa。又 R a ̸ = R b R_a \not= R_b Ra̸=Rb,所以 R b ⫋ R a R_b \subsetneqq R_a RbRa

于是, F a c Fac Fac中任意两串的 R i g h t Right Right集合,要么不相交,要么一个是另一个的真子集,要么完全相同。

那么,如果我们把所有的 R i g h t Right Right集合组成集合,我们可以把他们组织成一个树的结构(如上图)。我们把它叫做Parent树。

很明显,这棵树叶节点有n个,而每个非叶子节点至少有两个孩子(不存在只有一个孩子),易证树的大小为 O ( n ) O(n) O(n)级别(显然??)。

后面会用到的一些东西

令一个状态s,令 f a = P a r e n t ( s ) fa=Parent(s) fa=Parent(s)代表唯一的那个 R i g h t Right Right集合 R i g h t ( s ) Right(s) Right(s)父节点对应的集合的状态(这句话有点绕口,多读)。那么自然有 R i g h t ( s ) ⫋ R i g h t ( f a ) Right(s) \subsetneqq Right(fa) Right(s)Right(fa),并且 R i g h t ( f a ) Right(fa) Right(fa)的大小是其中最小的。

考虑 l e n ( S u b ( s ) ) len(Sub(s)) len(Sub(s)) l e n ( S u b ( f a ) ) len(Sub(fa)) len(Sub(fa))。则 l e n ( S u b ( s ) ) ∈ [ M i n ( s ) , M a x ( s ) ] len(Sub(s)) \in [Min(s),Max(s)] len(Sub(s))[Min(s),Max(s)]。考虑 M i n ( s ) − 1 Min(s)-1 Min(s)1为什么不可以,因为长度变短,限制条件变少,于是可出现的位置多了。假设 R i g h t ( s ) = R 1 Right(s)=R_1 Right(s)=R1,还是这幅图:

这是 M i n ( s ) − 1 Min(s)-1 Min(s)1的情况:

显然,这个变大后的 R i g h t Right Right集是所有包含 R 1 R_1 R1的集合中最小的一个。因此它就是 R i g h t ( f a ) Right(fa) Right(fa)因此, M a x ( f a ) = M i n ( s ) − 1 Max(fa)=Min(s)-1 Max(fa)=Min(s)1(L就是 M i n ( s ) Min(s) Min(s)

状态转移数线性的证明

我们已经证明了状态数是 O ( n ) O(n) O(n)的,为证明这是一个线性结构,还需证明它状态转移数也是 O ( n ) O(n) O(n)的。

  • t r a n s ( s , a ) = t trans(s,a)=t trans(s,a)=t,则s向t连一条标号为a的边(就是s->ch[a] = t)。

自己看CLJ课件去!

显然法:状态是 O ( n ) O(n) O(n)的,每个状态最多连出26条边,状态很显然是 O ( n ) O(n) O(n)的。

Part 3 构造

回顾定义与性质

  • 状态s,转移trans,初始状态init,终止状态集合end。
  • 母串S,S的后缀自动机SAM。
  • R i g h t ( s t r ) Right(str) Right(str)表示 s t r str str在母串中所有出现的位置右端点集合。
  • S u b ( s ) Sub(s) Sub(s)中所有子串 R i g h t Right Right集合相同,为 R i g h t ( s ) Right(s) Right(s)
  • P a r e n t ( s ) Parent(s) Parent(s) P a r e n t Parent Parent树。

对于一个状态s,它的 R i g h t ( s ) = { r 1 , r 2 , . . . , r n } Right(s)=\{r_1,r_2,...,r_n\} Right(s)={r1,r2,...,rn},现有s->ch[a]=t,考虑t的 R i g h t Right Right集合,由于t比s多一个字符,因此它限制更多, R i g h t ( t ) = { r i + 1 ∣ S [ r i ] = = c } Right(t)=\{r_i+1|S[r_i]==c\} Right(t)={ri+1S[ri]==c}

终于可以把这张大图下放了。

例如,对这个"ACADD"的SAM,若s = root->ch['a']t = s->ch['d'],那么 R i g h t ( s ) = { 1 , 3 } Right(s)=\{1,3\} Right(s)={1,3}(对应的后缀为"DD",“ACDD”), R i g h t ( t ) = { 4 } Right(t)=\{4\} Right(t)={4}(对应的后缀为"D"),显然符合前面所说规则。(记住下标从0开始)

同时,如果s出发有标号为x的边,那么 P a r e n t ( s ) Parent(s) Parent(s)出发也一定有(因为 s ⫋ P a r e n t ( s ) s \subsetneqq Parent(s) sParent(s))。

f = P a r e n t ( s ) f=Parent(s) f=Parent(s)。那么 R i g h t ( t r a n s ( s , c ) ) ⊂ R i g h t ( t r a n s ( f , c ) ) Right(trans(s,c)) \subset Right(trans(f,c)) Right(trans(s,c))Right(trans(f,c))(因为 s ⫋ f s \subsetneqq f sf)。

一个显然的推论是 M a x ( t ) &gt; M a x ( s ) Max(t)&gt;Max(s) Max(t)>Max(s)。(对t而言,如果不考虑 M i n ( t ) Min(t) Min(t),那么 l e n = M a x ( s ) + 1 len=Max(s)+1 len=Max(s)+1显然合适)

具体操作

  • S A M ( s t r ) SAM(str) SAM(str):str的后缀自动机

我们使用在线方法构造,即每次添加一个字符,使得当前SAM变成包含这个新字符的SAM(即,先构造 S A M ( S [ 0 , i ) SAM(S[0,i) SAM(S[0,i),再构造 S A M ( S [ 0 , i + 1 ) SAM(S[0,i+1) SAM(S[0,i+1))。

令当前字符串为T,新字符为x,令 l e n ( t ) = L len(t)=L len(t)=L

S A M ( T ) → S A M ( T x ) SAM(T) \rightarrow SAM(Tx) SAM(T)SAM(Tx)的过程中,这个SAM可以多识别一些原串S的子串,这些子串都是Tx的后缀。

Tx的后缀,就是在T的后缀后面接上字符x。

考虑所有可以表示T后缀(即, R i g h t Right Right集中包含L)的节点 v 1 , v 2 , v 3 , . . . v_1,v_2,v_3,... v1,v2,v3,...

由于必然存在一个 R i g h t ( p ) = L Right(p)=L Right(p)=L的状态p( p = S T ( T ) p=ST(T) p=ST(T)),那么由于 v 1 , v 2 , v 3 . . . v_1,v_2,v_3... v1,v2,v3... R i g h t Right Right集合中都含有L,那么它们在 P a r e n t Parent Parent树中必然全是p的祖先(由于 P a r e n t 树 的 性 质 Parent树的性质 Parent)。那么可以使用 P a r e n t Parent Parent函数得到它们。

同时我们添加一个字符x后,令 n p = S T ( T x ) np=ST(Tx) np=ST(Tx),则此时 R i g h t ( n p ) = L + 1 Right(np)=L+1 Right(np)=L+1

不妨设 v 1 = p , v 2 = P a r e n t ( v 1 ) , v 3 = P a r e n t ( v 2 ) , . . . , v k = P a r e n t ( v k − 1 ) = r o o t v_1=p,v_2=Parent(v_1),v_3=Parent(v_2),...,v_k=Parent(v_{k-1})=root v1=p,v2=Parent(v1),v3=Parent(v2),...,vk=Parent(vk1)=root R i g h t ( r o o t ) = [ 0 , L ] Right(root)=[0,L] Right(root)=[0,L])。

考虑其中一个v的 R i g h t Right Right集合 { r 1 , r 2 , . . . , r n } ( r n = L ) \{r_1,r_2,...,r_n\}(r_n=L) {r1,r2,...,rn}(rn=L),那么如果v->ch[x]=nv,则 R i g h t ( n v ) = { r i + 1   ∣   S [ r i ] = = x } Right(nv)=\{r_i+1\ |\ S[r_i]==x\} Right(nv)={ri+1  S[ri]==x}。同时,如果v->ch[x]=NULL,那么v的 R i g h t Right Right集合内就没有一个 r i r_i ri使得 S [ r i ] = = x S[r_i]==x S[ri]==x(先不考虑 v n v_n vn)。

又由于 R i g h t ( v 1 ) ⫋ R i g h t ( v 2 ) ⫋ R i g h t ( v 3 ) . . . Right(v_1) \subsetneqq Right(v_2) \subsetneqq Right(v_3)... Right(v1)Right(v2)Right(v3)...,那么如果v[i]->ch[x]!=NULL,那么v[j]->ch[x]也一定不是NULL( j &gt; i j&gt;i j>i)。

情况1

对于v->ch[x]==NULL的v,它的 R i g h t Right Right集合内只有 r n r_n rn满足要求,所以根据之前提到的规则,使得v->ch[x]=np

情况2

v p v_p vp v 1 , v 2 , v 3 , . . . v_1,v_2,v_3,... v1,v2,v3,...中第一个ch[x]!=NULL的状态。

考虑 R i g h t ( v p ) = { r 1 , r 2 , . . . , r n } Right(v_p)=\{r_1,r_2,...,r_n\} Right(vp)={r1,r2,...,rn},令 t r a n s ( v p , x ) = q trans(v_p,x)=q trans(vp,x)=q

那么 R i g h t ( q ) = { r i + 1 ∣ S [ r i ] = = x } Right(q)=\{r_i+1|S[r_i]==x\} Right(q)={ri+1S[ri]==x}(不考虑r_n)。

但是,我们不一定能直接在 R i g h t ( q ) Right(q) Right(q)中插入 L + 1 L+1 L+1(暂且不管如何插入)。

如果在 R i g h t ( q ) Right(q) Right(q)中直接插入 L + 1 L+1 L+1,由于限制条件增加,可能使 M a x ( q ) Max(q) Max(q)变小。

放图:

红色是结束在 R i g h t ( v p ) Right(v_p) Right(vp)位置上,长度为 M a x ( v p ) Max(v_p) Max(vp)的串,蓝色为结束在 R i g h t ( q ) Right(q) Right(q)位置上,长度为 M a x ( q ) Max(q) Max(q)的串。

于是强行做的话, M a x ( q ) Max(q) Max(q)变小就很显然了。

当然,如果 M a x ( q ) = = M a x ( v p ) + 1 Max(q)==Max(v_p)+1 Max(q)==Max(vp)+1,就不会有这样的问题(这个很显然,把上图蓝色串开头的A改成B就行了),直接插入即可。

怎么插入? P a r e n t ( n p ) = q Parent(np)=q Parent(np)=q

证明:很显然 R i g h t ( n p ) ⫋ R i g h t ( q ) Right(np) \subsetneqq Right(q) Right(np)Right(q)(q不会是 S T ( T ) ST(T) ST(T) L + 1 ∈ R i g h t ( q ) L+1 \in Right(q) L+1Right(q)),所以只需证明 R i g h t ( q ) Right(q) Right(q)是所有包含 R i g h t ( n p ) Right(np) Right(np)的集合中大小最小的。反证法,假设存在一个包含 R i g h t ( n p ) Right(np) Right(np)的集合 R i g h t ( f ) Right(f) Right(f),且 P a r e n t ( f ) = q Parent(f)=q Parent(f)=q,那么 M i n ( f ) = M a x ( q ) + 1 Min(f)=Max(q)+1 Min(f)=Max(q)+1,于是当 l e n = M a x ( q ) + 1 len=Max(q)+1 len=Max(q)+1时, l e n ∈ [ M i n ( f ) , M a x ( f ) ] len \in [Min(f),Max(f)] len[Min(f),Max(f)]。设 R i g h t ( q ) = { r 1 , r 2 , . . . , r k , . . . , r n } Right(q)=\{r_1,r_2,...,r_k,...,r_n\} Right(q)={r1,r2,...,rk,...,rn} R i g h t ( f ) = { r 1 , r 2 , . . . , r k , r n } Right(f)=\{r_1,r_2,...,r_k,r_n\} Right(f)={r1,r2,...,rk,rn},看图。

如果真是这样, R i g h t ( p ) Right(p) Right(p)不会是图上的 R i g h t ( p ) Right(p) Right(p),其中上方左数第一条边不应该存在(左数第三条可能也不存在)。因为只需要第2、4条边就可以使p->ch[x]!=NULL了,而这时第一条边显然还没有(加入它后Right§会变小)。于是产生矛盾,由此命题得证。

情况3

在2的情况下再减去一些限制条件又会怎样呢?

比如,现在没有了 M a x ( q ) = = M a x ( v p ) + 1 Max(q)==Max(v_p)+1 Max(q)==Max(vp)+1

这个条件这么好,没有了岂不是可惜?

没有条件,创造条件。

上图中,红色为 R i g h t ( v p ) Right(v_p) Right(vp),蓝色为 R i g h t ( q ) Right(q) Right(q),绿色为 R i g h t ( n q ) Right(nq) Right(nq)

我们把q拆成两份:新建一个节点nq,使 R i g h t ( n q ) = R i g h t ( q ) ∪ { L + 1 } Right(nq)=Right(q) \cup \{L+1\} Right(nq)=Right(q){L+1}。这时,我们可以证明 M a x ( n q ) = M a x ( v p ) + 1 Max(nq)=Max(v_p)+1 Max(nq)=Max(vp)+1,由于证法与上面那个证明非常类似所以不说了。

于是 R i g h t ( q ) , R i g h t ( n p ) ⫋ R i g h t ( n q ) Right(q),Right(np) \subsetneqq Right(nq) Right(q),Right(np)Right(nq),且 R i g h t ( n p ) + R i g h t ( q ) = R i g h t ( n q ) Right(np)+Right(q)=Right(nq) Right(np)+Right(q)=Right(nq)(图上可以看出)。于是, P a r e n t ( n p ) = P a r e n t ( q ) = P a r e n t ( n q ) Parent(np)=Parent(q)=Parent(nq) Parent(np)=Parent(q)=Parent(nq)

又由于 M i n ( q ) = M i n ( n q ) Min(q)=Min(nq) Min(q)=Min(nq)(感性认知),所以 P a r e n t ( n q ) = P a r e n t ( q ) Parent(nq)=Parent(q) Parent(nq)=Parent(q)(原来的)。

然后, t r a n s ( n q , x ) = t r a n s ( q , x ) trans(nq,x)=trans(q,x) trans(nq,x)=trans(q,x)(因为多出来的那个点再转移过程中没有用)。

接着,我们回头考虑 v 1 , v 2 , . . . , v k v_1,v_2,...,v_k v1,v2,...,vk这一序列。其中最早在 v p v_p vpch[x]!=NULL。于是乎只有一段 v p , . . . , v e v_p,...,v_e vp,...,ve(不是 v p , . . . , v k v_p,...,v_k vp,...,vk,因为 v e v_e ve之后 R i g h t ( v − &gt; c h [ x ] ) Right(v-&gt;ch[x]) Right(v>ch[x])会更大)通过x边转移到q。那么现在把这一段的 t r a n s ( ∗ , x ) trans(*,x) trans(,x)改为nq既可。

结束了!

//源文件竟有4000字了?

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值