字符串笔记

后缀系列

后缀自动机

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 最长公共子串对

原文地址:https://www.cnblogs.com/youddjxd/p/14545986.html