码迷,mamicode.com
首页 > 其他好文 > 详细

「SAM」你的名字

时间:2020-06-09 20:25:01      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:子串   世界   font   后缀   ext   观察   最大的   目的   sam   

  第二次做了

  回过头来看自己第一次写的代码简直一派胡言

  重新看的题解+骚扰Lrefrain解释代码,耗时一整天

  然后终于明白了,简直醍醐灌顶

  纪念之

  

  给定$S[]$,多次给定$T[],L,R$,询问$T$有多少本质不同的子串是在$S[L...R]$出现过的

  $|S|<=5e5 |T|<=1e6$

  

  首先考虑$L==1,R==n$的情况怎么做,

  一个直观的想法是拿$T$在$S$的$SAM$上跑

  然后沿路打上标记。然而$SAM$上的一个节点代表长度连续的多个串,可能并不能全部跑到

  所以要维护一个变量$plen$表示已匹配的长度,每个节点标记上有$min(plen,x->len)-x->f->len$串被跑到了

  然后再遍历所有跑过的节点累加就行了?

  既然已经注意到每个节点代表的多个子串中,跑到其中一个必定能跑到它的所有后缀

  不应该忽略$fail$树上此节点父链上所有的子串都是其后缀,都可以跑到

  所以每次都暴力跳父链打上$min(plen,x->len)-x->f->len$的标记,喜提$O(n^2)$

 

  发现跳父链的时候打上的标记全都是$x->len-x->f->len$,即全都包含

  则如果发现当前的x已经是这个标记了就不用再跳了,喜提$O(n\sqrt{n})$

  

  为什么这么不优秀,因为被打标记的节点数的上限是和$|S|$有关的,这不好

  不如只用$SAM(S)$维护$plen$,同时在$SAM(T)$上跑并打标记,喜提$O(n)$

  (其实全世界只有我一开始在$S$上打标记,所有人都想到了同时在$T$上跑。)

  

  然后若$L,R$任意,需要得到$SAM(S[L...R])$,但是不好做

  由于$SAM(S)$可以从$root$跑出$S$的所有子串,所以可以仍然依托$SAM(S)$的整体结构

  而用$endpos$集合来检查是否符合$[L,R]$的限制

  考虑怎么用$endpos$集合来达到等效目的,观察用$SAM(S)$做了什么

  1.寻找目前节点$x$有无字符$c$的出边,有就转移过去

    设目前完成匹配的子串为$C[1...plen]$,此时的$endpos$为$p$,

    若$C[1...plen]+c$仍在$S[L,R]$中,必满足

    $p-plen+1\in[L,R]$,$p\in[L,R]$

    即$L+plen-1<=p<=R$

    检查$x->son[c]$有无在区间$[L+plen,R]$中的$endpos$即可

    (由于此时$x=x->son[c],++plen$这行代码还未执行,$plen$还是未加字符$c$前的$plen_0$,不等式中的$plen=plen_0+1$)

  2.跳$x$的$parent$

    不论是$SAM(S[L...R])$还是整个串的$parent$树

    $x$的父链都包含了所有的$x->len$个后缀

    而整个串的$SAM$的可能更长一些,但是总的跳父亲次数怎么也不会超过$|T|$

    所以完全可以直接使用,不会遗漏任何出现过的最长后缀就完事了

  3.查询$x$的$len$

    首先思考真的需要查询$x$在$SAM(S[L,R])$的len吗?

    答案是否,只想要$T$在$S[L,R]$能维持最长多长的匹配,只是当$L=1,R=n$时,恰好等于$x->len$而已

    所以接下来求出来的并不是真正的$len$,而是最长匹配长度。

    

    首先在$[L,R]$中得有$endpos$

    考虑其中最大的$endpos$,设此节点所代表的 以这个位置为结尾的子串中 最长的一个为$skyh$

    如果$skyh$的左端点$>L$,则在$[L,R]$中的最长长度就等于整个串的$SAM$中这个节点的$len$了

    (可以理解为这个$endpos$)

「SAM」你的名字

标签:子串   世界   font   后缀   ext   观察   最大的   目的   sam   

原文地址:https://www.cnblogs.com/yxsplayxs/p/13080280.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!