我还是也写个吧,方便复习,太容易忘了我。。
构造
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也可以得到每个节点表示的子串个数;求每个节点表示的子串个数也可以从根节点向下更新,只是这样要每次枚举更新其所有儿子。
模式串如果多次匹配某点且不重复计算,要打个标记。