BISHI93 【模板】Trie 字典树¶
中等通过率 55.31%python3样例通过牛客 AC
讲解章节:Trie 字典树
一句话
n 个模式串,q 次询问「有多少模式串以 t 为前缀」。
解题思路¶
这题考什么¶
Trie(字典树,把公共前缀合并成一条路径的多叉树,见 73-Trie字典树)模板。插入每个模式串时,把它经过的每一个节点的 计数 +1;查询时沿 t 走下去,走得通就输出终点节点的计数, 走不通输出 0。因为「以 t 为前缀的串」恰好就是「插入时经过了 t 对应节点的串」。
数据规模与复杂度¶
n, q <= 1e5,所有串总长 <= 1e6,字符集是大小写字母(52 种,区分大小写)。 插入 + 查询都是 O(总长),共约 2e6 次转移。
Python 的实现选择(本题最关键的部分)¶
- 不要用「把每个前缀切出来当 dict 的 key」这种偷懒写法。 总长虽然只有 1e6,但可能是一个长度 1e6 的串, 切出它的全部前缀就是 5e11 次字符拷贝,直接爆炸;
- 也不要用「每个节点一个 dict」的 list-of-dict:最多 1e6 个节点, 1e6 个空 dict 光对象头就上百 MB;
- 这里用单个扁平 dict:key = node_id * 128 + 字符字节值,value = 子节点 id。 只有一个 dict、至多 1e6 个 entry,内存和常数都最优, 而且整数 key 的哈希是恒等映射,查得飞快;
- IO 用 sys.stdin.buffer.read().split():所有串都不含空格, 按 token 切正好一行一个。
坑在哪¶
- 区分大小写(样例里 "Way" 答案是 0 就是在测这个), 所以不能 lower(),直接用原始字节值当转移字符;
- 查询串可能比任何模式串都长,中途没有子节点就要立刻输出 0 并 break;
- cnt[节点] 统计的是「经过该节点的插入次数」,根节点(空前缀)不会被查到, 无需特殊处理。
参考实现¶
[:octicons-arrow-left-16: BISHI92](BISHI92.md) [BISHI94 :octicons-arrow-right-16:](BISHI94.md)