NOI2018-你的名字

题意

给定一个文本串ss,若干询问,每次询问给定一个区间[l,r][l,r]和一个模式串tt,求 tt 中不存在于sl...srs_l...s_r的字串个数。

s106,t106,q105|s| \leq 10^6 , \sum|t|\leq 10^6,q \leq 10^5

Solution

写三次SAM挂三次,全体目光向我看齐:我宣布个事! 我是个小可爱

先对ss建立一个SAM

Case1 : l=1,r=sl=1,r=|s|

全局情况,我们计算 tt 每一个前缀的贡献,具体地说,我们求一个fif_i表示 t1...it_{1...i}ss匹配的最大后缀长度(同类型题目SPOJ-LCS),这样对于每一个iitt上合法的串只存在于[1...ifi,i][1...i-f_i,i]中。

现在对tt单独建立一个SAM,对于每一个非根节点,都对应一个等价类,每一个等价类的贡献为

ans=max(0,lenimax(lenlinki,fidi))ans=\max(0,\operatorname{len_i} -\max(\operatorname{len_{link_i}},f_{\operatorname{id_i}}))

其中idi\operatorname{id_i}表示这个等价类的最小位置,具体的,idi\operatorname{id_i}为每次新建节点pp时的lenlast+1\operatorname{len_{last}}+1,在clone操作时直接复制。

复杂度O(s+t)O(|s|+\sum|t|)

Case2 :

现在加上区间限制。

首先发现区间限制仅影响对fif_i的求解,其余情况是不变的,它影响到是否将当前状态(p,l)(p,l)更新。

现给SAMs\operatorname{SAM_s}上标记idididiid_i表示sis_i对应的状态,同时在parent tree上跑dfs序。

假设现在状态处理到(p,l)(p,l),向cc转移,如果状态pp中存在一个向cc的转移,且lidl1rl\leq id-l-1 \leq r,那么就可以转移,同时根据parent tree的性质:根一定是子树节点的后缀,故若根有向cc的转移,子树节点也会有向cc的转移,倘若询问的rr非降,那么idid越大,则idl1id-l-1越大,所以维护子树最大值即可。

具体根据parent treedfn序建立线段树查询区间最大值。

所以对所有询问按照rr排序,维护最大值。

tips

但如果你真的按照例题的写法(指直接跳link\operatorname{link}),可能会得94pts94 pts(数据真水),为什么捏?

考虑判断转移是否可行的条件,为

  1. 有向cc的转移
  2. 最大值满足在区间内

如果条件1满足但条件2不满足,倘若直接跳link\operatorname{link},就会漏解

正确的做法是不断将l1l-1,直至l=linkpl=\operatorname{link_p},这时再跳link\operatorname{link}

Author: cjh-hhz
Link: https://cjh-hhz.github.io/07fce04ad229.html/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.