后缀系列
后缀自动机
1、parent_tree
对于某一个子串,在某一些位置(为结尾)出现过,出现过的所有位置集合叫做endpos。
parent_tree是这样一棵树:一个节点代表一个endpos集合,节点上的字符串的endpos全部相等且恰为该节点代表的endpos集合;
每一个节点的endpos集合都是父亲节点的子集。
可以发现一个性质:设每一个点上的子串的最长串长为maxlen,最短为minlen,则父亲的maxlen+1必然等于儿子的minlen,而且minlen~maxlen必然每一个len都对应一个子串。
可以证明parent_tree的节点个数为O(n)。
后缀自动机的节点就是parent_tree的节点。
2、后缀自动机
自动机本身是个DAG。
通过DAG上从初始点出发的每一条路径,都能组成一个子串,且所有子串都能被表示出来。
维护下列东西:
fa:parent_tree上的fa。
len:每个节点的maxlen(如上所阐述)(minlen可以通过fa的maxlen来得到)
ch:儿子。DAG上的边指向的点。一个点的ch数量就是字符集,每一个ch代表了:在上一个点的子串后接上一个字符获得的子串所属的点。
每次加入一个字符c,创立一个新节点:
首先,对于上一次加入的字符的初始点,若它和它的祖先们(parent_tree上的)都没有儿子c,那就把儿子c连向自己。
然后找到第一个已经有了儿子c的点x。
考虑这个点的儿子c,称为ch[x][c]:如果这个len[x]+1=ch[x][c],说明ch[x][c]里面存的东西正好是符合parent_tree定义的,把新节点的fa连向它;
否则,将x点拆成两个点u、v:len[u]+1=ch[x][c],len[v]=len[x];然后,v和新节点的fa都是u。u的fa就是x的fa。把连向x的ch中长度满足条件的连向u,长度不满足条件的连向v。u和v的ch和x是一样的。
这样就维护好了,可以证明边数也是O(n)的。
3、经典操作
parent_tree从下到上更新:
按照maxlen来对节点基数排序。
求两个串的最长公共子串:
在自动机上面跑(往下走ch、往上跳fa)就好了。注意nowlen的更新。
4、例题:
XSY3930 最长公共子串对