AC 自动机
做多模匹配其实就是把模式串丢到trie上,然后设置一个fail指针。
fail指针的含义是:最长的与后缀相同的前缀
明显,由于是最长的一个点的fail只会只想一个点(两个相同的前缀是一个点啊)
一个结论:如果沿着一个点一直跳fail,会得到这个串在ac自动机上的所有后缀
求出fail的过程是用bfs实现的。考虑一个节点 p 假设所有满足$len[s] < len[p]$的节点$s$的fail 指针都已经被计算出来了,它的父亲设为 f ,父亲到这个点的路径上字符是 C ,如果 fail[f] 拥有子树 C ,那么可以直接指向这个子树(这个贪心类似kmp)。如果并不拥有,就需要一直跳 fail 直到找到一个这样的位置。
一个很好的处理方式是,如果一个点没有指向某个字符 C 的路径,就加一个从这里到 这个点的fail通过C走到的点。然后这个trie就彻底变成了一个图,这样可以不用暴力跳fail建树,可以直接指向这个子树了(因为如果原本这个子树没有东西也已经变成了这个子树可以跳到的第一个有C这个子树的点)。同时这样处理后匹配的时候也不用跳fail了直接跑就可以了。代码就加一行:son[cur][i] = son[fail[cur]][i];
但是注意到要匹配 aaabb
,原本aabb
和 abb
本来都该被匹配但是匹配到 aabb
时就结束了。
为了解决这个问题,一个简单的方法是匹配到后跳一下fail,可是这样是可以被卡的(就算跳last好像也会被卡),可以考虑把每个点的父亲设置为它的fail,然后树上差分就可以解决问题。