我還是也寫個吧,方便復習,太容易忘了我。。
構造
why if(len[q]!=len[p]+1) nq=++tot。
\(q\)和\(p\)之間還有更短的串,\(q\)不是第一個能接\(nowc\)的串,所以新建一個節點\(nq\)將\(nowc\)連上。
從后綴樹角度:原先\(nq\)相當於只有一個子節點,可以被壓縮,而加入了\(nowc\)后就有兩個孩子了。
性質
1.每個狀態(節點)代表的所有串在原串中的出現次數和每次出現的右端點集合相同;節點p所代表字符串的長度為依次取 \((\ len[fa[p]],len[p]\ ]\) 中每一個數;\(len_{min}[p]=len_{max}[fa[p]]+1\)。
(每個節點代表的串即根節點到達該點的任意一條路徑形成的串。這個串與其他路徑形成的串不同。 )
2.\(SAM\)的點數不超過\(2n-2\),邊數不超過\(3n-3\)。
3.parent樹,就是翻轉字符串\(s\)后建立的后綴樹(也是原串的反向前綴樹)。
4.兩個串的最長公共后綴的狀態,位於這兩個串狀態在parent樹上的LCA處。
5.從根節點按字典序遍歷可以得到原串的所有子串。
6.每個點的 \(right\) 是其子樹所有點的 \(right\) 的並集。即 \(right(p)\subset right(fa[p])\)(parent樹上子節點的right是父節點的子集)。
7.\(SAM\)的狀態和轉移構成了一個有向無環圖。常利用拓撲排序求到達某點的路徑數。
應用
https://blog.csdn.net/clover_hxy/article/details/68059043。
最長公共子串
兩個串的最長公共子串:SPOJ1811 LCS
多個串的最長公共子串:SPOJ1812 LCS2
### 第K小子串 [BZOJ3998 弦論](https://www.cnblogs.com/SovietPower/p/9118571.html) [BZOJ2882 工藝](https://www.cnblogs.com/SovietPower/p/9241275.html)
### 重復出現子串 [POJ1743 Musical Theme](https://www.cnblogs.com/SovietPower/p/8569121.html) [BZOJ2555 SubString](https://www.cnblogs.com/SovietPower/p/9239427.html)
### 廣義后綴自動機 [BZOJ3926 [ZJOI2015]諸神眷顧的幻想鄉](https://www.cnblogs.com/SovietPower/p/9240424.html) [hihoCoder1457 后綴自動機四·重復旋律7](https://www.cnblogs.com/SovietPower/p/9329499.html) [BZOJ2780 Sevenk Love Oimaster](https://www.cnblogs.com/SovietPower/p/9240586.html) [BZOJ3277 串](https://www.cnblogs.com/SovietPower/p/9241115.html)
### parent樹與right集合 通常是利用parent樹與right集合處理計數問題。 [hihoCoder1465 后綴自動機五·重復旋律8](https://www.cnblogs.com/SovietPower/p/9330268.html) [BZOJ4516 [SDOI2016]生成魔咒](https://www.cnblogs.com/SovietPower/p/9241663.html) [BZOJ4566 [HAOI2016]找相同字符](https://www.cnblogs.com/SovietPower/p/9241813.html) [BZOJ1396 識別子串](https://www.cnblogs.com/SovietPower/p/9248486.html)
### SAM與DP [BZOJ3238 [AHOI2013]差異](https://www.cnblogs.com/SovietPower/p/9249744.html) [BZOJ4180 字符串計數](https://www.cnblogs.com/SovietPower/p/9249426.html) [BZOJ4032 [HEOI2015]最短不公共子串](https://www.cnblogs.com/SovietPower/p/9320442.html) [BZOJ2806 [CTSC2012]Cheat](https://www.cnblogs.com/SovietPower/p/9329071.html)
### 神仙題 各種結合(其實也就是與線段樹...?) 好吧也已經成了套路了? [CF666E Forensic Examination](https://www.cnblogs.com/SovietPower/p/9368392.html) 對於匹配多個串(廣義SAM),要求S在哪個串中出現最多,可以先求每個節點貢獻|right|最大的是哪個串,然后用S匹配到一個節點。 具體是,每個點建線段樹,每插入一個字符,在插入位置的當前串處+1並Update更新答案。線段樹可以合並子節點的|right|,也可以區間查! 求S的某區間匹配到哪個點,可以先匹配1~r,然后倍增找到恰好匹配l~r的點。 [NOI2018 你的名字](https://www.cnblogs.com/SovietPower/p/9821733.html)
### 注 把一個串在SAM上匹配,就可以得到以某個位置作為后綴,其最長可匹配的長度。
在parent樹上(或是按拓撲序)自底向上更新可以得到某個位置的right大小,乘對應的len也可以得到每個節點表示的子串個數;求每個節點表示的子串個數也可以從根節點向下更新,只是這樣要每次枚舉更新其所有兒子。
模式串如果多次匹配某點且不重復計算,要打個標記。
