\(1.init:\)初始狀態。數組
\(2.end:\)結束狀態。數據結構
\(3.E:\)結束狀態\(end\)集合。spa
\(4.fa(s):parent\)樹上\(s\)的父親節點。排序
\(5.Reg(s):\)節點\(s\)能達到的\(end\)的集合。字符串
\(6.mx(s):\)節點\(s\)所表明的子串的最長長度。it
\(7.mn(s):\)節點\(s\)所表明的字串的最短長度。class
\(8.Right(s):\)狀態\(s\)出現的右端點集合。數據
\(9.ST(s):\)節點\(s\)能到達的狀態集合(點數)。查詢
\(1.Right(s)\subset Right(fa(s))\)集合
\(2.mn(s) = mx(fa(s))+1\)
\(3.s\)所表明的全部串在母串中出現的次數和每次出現的右端點相同。
\(4.\)後綴自動機的\(parent\)樹是原串的反向前綴樹(把每一個前綴的反串插入到\(Trie\)樹中,而且把沒有分支的鏈合併)。
若\(\exists e(u,v)\) 則 \(mx(u) < mx(v)\);若\(fa(v)=u\)也能獲得\(mx(u) < mx(v)\)。因此將節點按照\(mx\)數組排序,能夠獲得拓撲序(基排\(O(n)\))。
若只求大小,能夠按照逆拓撲序遞推;若是還須要求具體節點,須要平衡樹(啓發式合併)/可持久化平衡樹;若是須要動態維護\(|Reg(s)|\)(創建的同時維護),則須要一個數據結構,支持在有根樹上加邊刪邊,求子樹和,由於有根把子樹和轉化成鏈上加減,單點查詢而後\(LCT\)便可。
逆拓撲序遞推,若求本質不一樣,則每一個狀態貢獻1;若相同算屢次,則每一個狀態貢獻\(|Right|\)次。
\(1.\)求本質不一樣子串數量:\(\sum_{s}mx(s) - mn(s) + 1\)。
\(2.\)求字符串的最小表示:先對\(S+S\)創建\(SAM\),而後在\(SAM\)上跑,每次貪心走字典序最小的出邊,走\(|S|\)步便可。
\(3.\)求兩個字符串的最長公共子串:對一個串創建\(SAM\),而後跑匹配,若是失配則跳\(fa\)。
\(4.\)求後綴樹和後綴數組:把反串建\(SAM\)而後\(parent\)樹就是後綴樹,後綴樹上\(dfs\)獲得後綴數組。
\(5.\)字典序\(k\)小子串:求\(ST\)而後相似線段樹二分的去作。
\(6.\)求本質不一樣的子串總長:\(\sum_{s}\sum_{i=mn(s)}^{mx(s)}i\)