\(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\)