后缀自动机的应用

零.前置:

\(1.init:\)初始状态。

\(2.end:\)结束状态。

\(3.E:\)结束状态\(end\)集合。

\(4.fa(s):parent\)树上\(s\)的父亲节点。

\(5.Reg(s):\)节点\(s\)能达到的\(end\)的集合。

\(6.mx(s):\)节点\(s\)所代表的子串的最长长度。

\(7.mn(s):\)节点\(s\)所代表的字串的最短长度。

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

三.如何求Right(s):

若只求大小,可以按照逆拓扑序递推;如果还需要求具体节点,需要平衡树(启发式合并)/可持久化平衡树;如果需要动态维护\(|Reg(s)|\)(建立的同时维护),则需要一个数据结构,支持在有根树上加边删边,求子树和,因为有根把子树和转化成链上加减,单点查询然后\(LCT\)即可。

三.如何求ST(s):

逆拓扑序递推,若求本质不同,则每个状态贡献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\)

\({\color{red}{\text{咕}}}{\color{green}{\text{咕}}}{\color{blue}{\text{咕}}}{\color{brown}{\text{咕}}}{\color{gold}{\text{咕}}}{\color{grey}{\text{咕}}}{\color{purple}{\text{咕}}}{\color{pink}{\text{咕}}}{\color{red}{\text{咕}}}{\color{green}{\text{咕}}}{\color{blue}{\text{咕}}}{\color{brown}{\text{咕}}}{\color{gold}{\text{咕}}}{\color{grey}{\text{咕}}}{\color{purple}{\text{咕}}}{\color{pink}{\text{咕}}}\)

posted @ 2019-04-12 20:30  Smeow  阅读(325)  评论(0编辑  收藏  举报