后缀树
我们考虑将一个串的所有后缀插入一个trie中,得到的trie就是后缀trie。我们可以发现,树上有分叉或者是后缀节点的点的个数是 O ( l e n ) O(len) O(len)个,这个后面解释,于是把没有分支并且不是后缀节点的点压缩到一起,就变成了后缀树。
不难发现,后缀树可以表示该字符串的所有子串。
下面分析一下后缀树的一些性质
-
后缀树一个节点表示的串出现次数相同。(不然为什么能缩到一起)。
-
后缀树按照‘a’ - ‘z’遍历得到的dfs序就是将原串所有子串按照字典序从小到大排序得到的序列。
有人会问,为什么有后缀树,没有前缀树?我只能说,呵呵。
构造
不会正常的 O ( n l o g n ) O(nlogn) O(nlogn)构造,但是我们可以通过构造后缀自动机来构造,实际上我们知道,一个串后缀自动机的parent树,实际上就是其反串的后缀树,由于后缀自动机节点是 O ( l e n ) O(len) O(len)的,所以后缀树节点也是 O ( l e n ) O(len) O(len)的。
利用后缀树可以轻松的解决一些与字典序相关的问题,这里随便说一下,比如查询字典序排第k大的是那个,很明显,二分。如果查询某个串的排名,先走到对应节点,然后看这个节点的dfs序之类的就可以了。
后缀数组
我们将所有后缀排序,得到一个序列,设为sa,sa[i]表示排名为i的串是那个后缀,由于后缀长度互不相同,所以排序结果唯一。后缀排序可以通过刚才建后缀树的方法,可以不去写网上常见的倍增做法。
再定义 h e i g h t [ i ] = l c p ( S [ s a [ i − 1 ] , n ] , S [ s a [ i ] , n ] ) height[i] = lcp( S[sa[i - 1] ,n] , S[sa[i] , n] ) height[i]=lcp(S[sa[i−1],n],S[sa[i],n]),以及 r n k [ i ] = 后 缀 i 的 排 名 rnk[i] = 后缀i的排名 rnk[i]=后缀i的排名。
我们可以知道
h
e
i
g
h
t
[
r
n
k
[
i
]
]
≥
h
e
i
g
h
t
[
r
n
k
[
i
−
1
]
]
−
1
height[rnk[i]] \geq height[rnk[i-1]] - 1
height[rnk[i]]≥height[rnk[i−1]]−1,然后就可以计算height了。至于有什么用,主要用处就是
h
e
i
g
h
t
height
height。
但是博主太菜,没找到什么只能用后缀数组,而不能用后缀树或者后缀自动机搞的题目,或者用后缀数组明显好做的题目,望有人告知博主。