Trie 树CSP-S

目录

💡 核心思想

Trie(前缀树/字典树)是一种树形数据结构,每条边代表一个字符,从根到某节点的路径上的字符组成一个字符串。支持 $O(|s|)$ 的插入、查询和前缀匹配。变体包括 01-Trie(处理异或问题)。

Trie 的核心思想是"共享前缀"。如果你插入 "abc" 和 "abd",它们共享 "ab" 这条路径,只在最后分叉。这使得前缀查询非常高效。01-Trie 是 Trie 的二进制版本,每个节点只有 0/1 两个儿子,常用于求最大异或和。

🎯 直觉理解

Trie 就像一本字典的目录结构。所有以 "ab" 开头的单词共享 "a→b" 这个前缀路径,然后在 "b" 后面根据下一个字母分叉。查找某个前缀是否出现过,只需要沿路径走一遍就行。

📝 算法流程

  1. 插入:沿字符路径走,不存在则创建新节点
  2. 查询:沿路径走,走不到则不存在
  3. 每个节点维护 son[26] 和 end 标记
  4. 01-Trie:son[2],处理二进制位

$$\text{Trie 空间:} O(\text{总字符数} \times |\Sigma|)$$

📊 复杂度分析

指标复杂度
时间$O(|s|)$ 每次操作
空间$O(N \cdot |\Sigma|)$($N$ 为总字符数)

💻 参考实现(C++)

C++ (C++17)
#include <bits/stdc++.h>
using namespace std;
int trie[1000005][26], tot = 1;
bool End[1000005];
void insert(const string& s) {
    int p = 1;
    for (char c : s) {
        int ch = c - 'a';
        if (!trie[p][ch]) trie[p][ch] = ++tot;
        p = trie[p][ch];
    }
    End[p] = true;
}
bool search(const string& s) {
    int p = 1;
    for (char c : s) {
        int ch = c - 'a';
        if (!trie[p][ch]) return false;
        p = trie[p][ch];
    }
    return End[p];
}
int main() {
    int n; cin >> n;
    while (n--) {
        string op, s; cin >> op >> s;
        if (op == "insert") insert(s);
        else cout << (search(s) ? "Yes" : "No") << "\n";
    }
    return 0;
}

⚠️ 常见坑点

数组大小要开够:节点数 = 所有字符串长度之和

字符集大小不同时 son 数组大小要调整

01-Trie 要从高位到低位处理

删除操作需要维护引用计数

📚 相关题目

题目来源难度备注
P8306 字典树洛谷CSP-STrie模板
P4551 最长异或路径洛谷CSP-S01-Trie