NOI2018 你的名字
NOI2018 你的名字
给定两个串 \(S\) 和 \(T\),查询 \(T\) 的所有子串有多少个不是 S 的子串。
其中,\(S\) 的给出方式为给定一个串 \(S'\),每次查询的 \(S\) 为 \(S'\) 的一个区间。
\(\rm Sol:\)
考虑计算:\(T\) 的本质不同的子串数量减去 \(T\) 在 \(S\) 中出现过的字串数量。
对于每个后缀 \(i\),预处理一个 \(nxt_{i}\) 表示 \([i,nxt_i]\) 都在 \(S\) 中出现过。
同时这个 \(nxt_i\) 是极长的。
那么建立后缀树,我们就可以知道这样的一个后缀的前缀是在 S 中出现过的,于是直接在后缀树上染色即可。
问题在于预处理 \(nxt_i\)
考虑枚举 \(i\),问题等价于找一个 \([i,nxt_i]\) 使得其在 \(S\) 中出现过。
建立 \(S\) 的后缀树,假设从对 T 从 \(1\) 开始扫描,不难发现 \(nxt_i\) 不会降低。
于是直接拿双指针扫描即可。
对于区间的形态,假设当前长度为 \(\rm len\),区间为 \([L,R]\),那么等价于使得后缀 \([L,R-\rm len+1]\) 出现过,对 S 按照 dfs 序建立主席树,就做完了。
复杂度是 \(\mathcal O(\sum |T|\log n+|S|\log n)\)