后缀自动机 学习笔记
我还是也写个吧,方便复习,太容易忘了我。。
构造
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小子串
重复出现子串
POJ1743 Musical Theme
BZOJ2555 SubString
广义后缀自动机
BZOJ3926 [ZJOI2015]诸神眷顾的幻想乡
hihoCoder1457 后缀自动机四·重复旋律7
BZOJ2780 Sevenk Love Oimaster
BZOJ3277 串
parent树与right集合
通常是利用parent树与right集合处理计数问题。
hihoCoder1465 后缀自动机五·重复旋律8
BZOJ4516 [SDOI2016]生成魔咒
BZOJ4566 [HAOI2016]找相同字符
BZOJ1396 识别子串
SAM与DP
BZOJ3238 [AHOI2013]差异
BZOJ4180 字符串计数
BZOJ4032 [HEOI2015]最短不公共子串
BZOJ2806 [CTSC2012]Cheat
神仙题 各种结合(其实也就是与线段树...?)
好吧也已经成了套路了?
CF666E Forensic Examination
对于匹配多个串(广义SAM),要求S在哪个串中出现最多,可以先求每个节点贡献|right|最大的是哪个串,然后用S匹配到一个节点。
具体是,每个点建线段树,每插入一个字符,在插入位置的当前串处+1并Update更新答案。线段树可以合并子节点的|right|,也可以区间查!
求S的某区间匹配到哪个点,可以先匹配\(1\sim r\),然后倍增找到恰好匹配\(l\sim r\)的点。
NOI2018 你的名字
注
把一个串在SAM上匹配,就可以得到以某个位置作为后缀,其最长可匹配的长度。
在parent树上(或是按拓扑序)自底向上更新可以得到某个位置的right大小,乘对应的len也可以得到每个节点表示的子串个数;求每个节点表示的子串个数也可以从根节点向下更新,只是这样要每次枚举更新其所有儿子。
模式串如果多次匹配某点且不重复计算,要打个标记。
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------