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)\)

posted @ 2020-09-11 19:12  Soulist  阅读(110)  评论(0)    收藏  举报