题意
给定一个文本串s,若干询问,每次询问给定一个区间[l,r]和一个模式串t,求 t 中不存在于sl...sr的字串个数。
∣s∣≤106,∑∣t∣≤106,q≤105
Solution
写三次SAM
挂三次,全体目光向我看齐:我宣布个事! 我是个小可爱
先对s建立一个SAM
Case1 : l=1,r=∣s∣
全局情况,我们计算 t 每一个前缀的贡献,具体地说,我们求一个fi表示 t1...i和s匹配的最大后缀长度(同类型题目SPOJ-LCS),这样对于每一个i,t上合法的串只存在于[1...i−fi,i]中。
现在对t单独建立一个SAM
,对于每一个非根节点,都对应一个等价类,每一个等价类的贡献为
ans=max(0,leni−max(lenlinki,fidi))
其中idi表示这个等价类的最小位置,具体的,idi为每次新建节点p时的lenlast+1,在clone
操作时直接复制。
复杂度O(∣s∣+∑∣t∣)
Case2 :
现在加上区间限制。
首先发现区间限制仅影响对fi的求解,其余情况是不变的,它影响到是否将当前状态(p,l)更新。
现给SAMs上标记id,idi表示si对应的状态,同时在parent tree
上跑dfs
序。
假设现在状态处理到(p,l),向c转移,如果状态p中存在一个向c的转移,且l≤id−l−1≤r,那么就可以转移,同时根据parent tree
的性质:根一定是子树节点的后缀,故若根有向c的转移,子树节点也会有向c的转移,倘若询问的r非降,那么id越大,则id−l−1越大,所以维护子树最大值即可。
具体根据parent tree
的dfn
序建立线段树查询区间最大值。
所以对所有询问按照r排序,维护最大值。
tips
但如果你真的按照例题的写法(指直接跳link),可能会得94pts(数据真水),为什么捏?
考虑判断转移是否可行的条件,为
- 有向c的转移
- 最大值满足在区间内
如果条件1
满足但条件2
不满足,倘若直接跳link,就会漏解
正确的做法是不断将l−1,直至l=linkp,这时再跳link