「gym103483」C. How Many Strings Are Less

Description

Link:gym103483 C

给出一个包含 nn 个字符串的集合 DD 以及一个字符串 ss,你需要找出集合 DD 中字典序小于 ss 的字符串数量。

字符串 ss 会经过 QQ 次修改,每次修改会给出一个整数 kk 以及一个字符 cc,表示将字符串 ss 从第 kk 个字符开始到字符串末尾的所有字符替换成 cc。每次修改完字符串 ss 之后,你都需要求出集合 DD 中字典序小于 ss 的字符串数量。

数据范围:1n,Q1061 \leq n, Q \leq 10^61s1061 \leq |s| \leq 10^6,字符串集合 DD 的总长不超过 10610^6

时空限制:22s / 512512MiB。

Solution

考虑建出 Trie 树,设 cnt[u]\mathrm{cnt}[u] 表示节点 uu 上的终止节点个数,设 sze[u]\mathrm{sze}[u] 表示节点 uu 的子树内的终止节点个数。

go(u,c)\mathrm{go}(u, c) 表示节点 uu 往节点 δ(u,c)\delta(u, c) 走产生的贡献,则 go(u,c)=cnt[u]+i<csze[δ(u,i)]\mathrm{go}(u, c) = \mathrm{cnt}[u] + \sum_{i < c} \mathrm{sze}[\delta(u, i)]

考虑把贡献记在点上,即 value(δ(u,c))=go(u,c)\mathrm{value}(\delta(u, c)) = \mathrm{go}(u, c),则一个字符串 ss 对应的答案即为其在 Trie 树上经过的节点的贡献之和(叶子需要特殊考虑)。

于是我们只需维护字符串 ss 在 Trie 树上的位置即可。维护 end(u,c)\mathrm{end}(u, c) 表示节点 uu 一直沿着字符 cc 走到达的节点。使用 end\mathrm{end} 数组向下走,再使用树上倍增向上走。特别处理一下叶子节点的贡献(即字符串 ss 走出了 Trie 树)即可。

MENASQ_TGRM 大佬的优秀做法:在 end(u,c)\mathrm{end}(u, c) 中约束向下走到达的节点深度,深度 n\leq n 即可。