Trie树
Trie(字典树)是一种用于实现字符串检索的多叉树。
Trie的每一个节点都可以通过 c 转移到下一层的一个节点。
我们可以看作可以通过某个字符转移到下一个字符串状态,直到转移到最终态为止。这是后话……
我们以插入了字符串 ab,aa,b 三个字符串的Trie树为例:

其实一看图就非常清晰了
在上图中,如果我们需要继续插入一个字符串 abc,那么就只需要新建一个节点即可

思路清晰,那么代码如何实现?
- 首先是插入部分:
struct Node {
int kids[65];
int cnt;
} nodes[N];
#define kids(p, j) nodes[p].kids[j]
#define cnt(p) nodes[p].cnt
void insert(char * s, int len) {
int p = 0;
for (int i = 0; i < len; ++i) {
int j = discrete(s[i]);
if (!kids(p, j)) kids(p, j) = ++usage; // 新建节点
p = kids(p, j);
}
++cnt(p);
}
discrete指的是离散化,例如这里是将
a-z用0-25表示
最终的 cnt 表示有几个字符串在当前节点结束。
- 然后是查询部分
我们还是利用类似的思路,一个一个向下走。
例如我们要查询字符串 aba,那么我们从根节点 0 开始,通过 a 走到 1 节点,通过 b 走到 4 节点,发现没有 a 的子节点,表明没有这个字串,结束寻找。
// 这里是查询这个字符串出现了多少次,为0就是没有出现
int count(char * s, int len) {
int p = 0;
for (int i = 0; i < len; ++i) {
int j = discrete(s[i]);
if (!kids(p, j)) return 0;
p = kids(p, j);
}
return cnt(p);
}
其实主要操作就这两个,我们考虑一下空间和时间复杂度:
时间复杂度很明显是与字符串长度相关的,我们每处理一个字符走一个节点,也就是 $O(L)$ 的复杂度,那么总的复杂度就是 $O(NL)$
至于空间复杂度,每处理一个字符串至多新建 $L$ 个节点,那么就是 $O(L)$ ,每一个节点的大小关乎字符串的字符集大小,所以我们认为是 $O(C)$ 那么总共就是 $O(NLC)$ ,但是,在实际中,远远达不到此复杂度(除非毒瘤出题人想卡你),例如最初的图,一共 4 个字符串,但是只有 5 个节点……
例题
注意题意,以询问所给作为前缀,求有多少个字符串满足此前缀
那么我们需要魔改一下
insert函数即可……将++cnt(p)放入循环中即可还请读者仔细思考
这道题非常的神奇……考虑先建Trie树,如果某一个字符串的字典序比其他任何字符串都大,那么一定不存在为其前缀的字符串。
再考虑字典序,如果使
s其字典序最大,那么每一个分叉点上,s[i]比其他所有存在的分叉都要大。如样例:
omm,moo,mom。如果要使
omm最大那么在第一层上满足o > m,其他层上没有分叉。如果要使
moo最大,那么第一层上满足m > o,第三层上满足o > m,条件相悖,所以不可行。其他同理。
那么我们如何判断条件相悖?可以借鉴
2-SAT的思路,通过大于关系建图,如果存在环,那么不可行。判环用拓扑,谁用Tarjan啊
最终,每一个串判断一遍即可。
这道题就是Trie的一种特殊用法。
有点类似线段树的区间标记。
我们考虑改变一个规则对其整个子树都有影响,那么我们考虑什么时候影响抵消?更深的点会阻挡了标记的下传。那么我们记录一下各个点的标记情况,通过类似线段树的方法下传标记即可。
正确性显然。
扩展
Trie 树实际上是 AC自动机 和 回文自动机 等自动机的载体,需要经过一点点小变换。
在此不展开叙述,详见我的其他文章:
01 Trie
可以检索字符串,那么自然也可以检索二进制数。
这是一种支持 $O(\log V)$ 进行如下种种操作的数据结构:
查询是否存在(【模板】普通平衡树 - 洛谷,我在 算法学习笔记(21): 平衡树(二) - jeefy - 博客园 中谈过其使用方法)
查询前驱后缀
查询第 $k$ 大,以及 $x$ 的排名
查询与 $x$ 异或的第 $k$ 大(参见 [十二省联考 2019] 异或粽子 - 洛谷)
查询最大异或对(ACWing 最大异或对)
可持久化
……
如果倒着建树,那么还可以完成以下操作:
- 全局 $+1$,单点修改(参见 [Ynoi2010] Fusion tree - 洛谷)
其实通过一些方法可以做到亚 $\log$,参见 2021 论文《浅谈亚 log 数据结构在 OI 中的应用》。可以看一些博文:压位 Trie 学习笔记 - DPairの博客 - 洛谷博客
原论文可在:https://rusunoi.github.io/books/National-Team-Thesis/2021.pdf 下载。
