关于后缀自动机的理解

一个点表示一个终点集合,即表示一段连续长度的后缀,其后缀链接指向最大长度为minlen-1的点

clone就是因为在len[p]+1<len[q]的情况下,cur的后缀链接并不能直接指向q,这样会导致不合法的后缀出现

所以clone q,把原来q的后缀分成两部分,一部分是len<=len[p]+1的,另一部分是len>len[p]+1的

这也是为什么要把p的后缀链接中点重定向的原因,len<=len[p]+1的点一定在p的后缀链接中,为了确保len<=len[p]+1的后缀全都被分到clone q的管辖范围内

重定向的时候遇到没有指向q的就停止,是因为p指向q,而当前点不指向q,所以当前点的后缀肯定也不会指向q

 

一个路径表示一个子串

一个子串S[L:R]对应的后缀自动机中的点一定是R对应的点的祖先

两个前缀S,T的LCS即len[后缀链接树上的LCA(S对应点,T对应点)]

 

广义后缀自动机在last=0后新建点时先判断是否已经有对应的转移边,如果存在并且len[p]+1=len[q],那么不用新建点,直接把对应的位置指向q即可;如果存在但是len[p]+1!=len[q],那么新建一个点,类似clone转移,把对应位置指向新建点。

如果广义后缀自动机仍然按照原来的建法(除了令last=0外不改变任何操作),那么可能会出现一些普通后缀自动机没有的情况:

会出现“凌空节点”即没有任何转移边连向新建点,而它的 fail 指向了一个跟它相同的字符,比如说aaa aaaa的广义SAM

会存在len[x]=len[y],而 fail[y] = x,所以此时不能按照 len 桶排序来确定顺序

插入时定位只对第一个串有效,后面的串的定位需要往上找到 len 相同的最浅的点。但沿转移边匹配后定位仍然有效。

 

出现次数查询

问题.给定文本T,询问格式如下:给定字符串P,希望找出P作为子串在文本T中出现了多少次(出现区间可以相交)。

复杂度要求.预处理O(length(T)),单次询问O(length(P)).

算法.我们将文本T建立后缀自动机。

然后我们需要进行预处理:对自动机中的每个状态v都计算cnt[v],等于其endpos(v)集合的大小。事实上,所有在T中对应同一状态的字符串都在T中出现了相同次数,该次数等于endpos中的位置数。

不过,我们无法对所有状态明确记录endpos集合,所以我们只计算其大小cnt.

为了实现这一点,如下处理。对每个状态,如果它不是由“拷贝”而来,最初就赋值cnt=1.然后我们按长度len降序遍历所有序列,并将当前的cnt[v]加给后缀链接:

cnt[link(v)]+=cnt[v].

你可能会说我们并没有对每个状态计算出了正确的cnt值。

为什么这是对的?不经“拷贝”而来的状态恰好有length(S)个,而且其中的第i个是我们添加第i个字符时得到的。因此,最初这些状态的cnt=1,其他状态的cnt=0.

然后我们对每个状态v执行如下操作:cnt[link(v)]+=cnt[v].其意义在于,如果某字符串对应状态v,曾在cnt[v]中出现过,那么它的所有后缀都同样在其中出现。

这样,我们就掌握了如何对自动机中所有状态计算cnt值的方法。

在此之后,询问的答案就变得平凡——只需要返回cnt[t],其中t是模式串P所对应的状态。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值