20260813 - 字典树
今天居然没有罚时诶,两个 CE 居然不算!
写 Trie 时应该思考什么
- Trie 中的一个节点代表什么?
- 每一个节点的下一个节点,是否是结尾
- 从根到一个节点的路径代表什么?
- 存入字符串的前缀。
- 一个节点的子树代表哪个字符串集合?
- 代表以根到该节点的路径所代表的前缀为前缀的字符串集合。
cnt[u]和ed[u]有什么区别?- 前面的是经过点的个数,后面的结尾的个数。
- 为什么把整数写成二进制后,也可以建立 Trie?
- 因为写成 \(0/1\) 后可以更好地处理二进制问题。
- 什么题适合 Trie,什么题不适合?
- 一般前缀相关的问题都可以通过 Trie 来解决,非前缀比如字符串匹配等问题就不能使用。
令人欣慰的是,今天的字典树代码强度直线下降。
顺带一提,trie 在英式英语中读作 /triː/,在美式英语中读作 /traɪ/,所以 mmt 说的 try 也是有道理的。
A - trie模板
事实证明,封装的 trie 也是有好处的,这样不用每次维护了。
枚举每篇短文,将其所有单词丢进 Trie 里边,然后直接找就行了。
B - Karuta
显然,每个点最大的 LCP 就是离他最近的分叉口,可以用树形 DP 维护。
分叉维护可以在字典树上维护。
C - Secret Message G
观察到,前缀长度等于字符串中较短的长度,分两种情况:如果消息长度比暗号要短,那么去把前缀的 end 数组累加起来;如果消息长度比暗号要长,那么暗去把结尾的 count 数组加进去。
D - Yet Another Sigma Problem
由于子树子串的个数就是在 LCA 位置的个数,所以每次插入的时候直接加上个数。
E - 01trie模板
我们发现异或两次等于没有异或,所以可以考虑每个点到根的异或和。
如果最高位还更大,那么其他位置再大也没有用。
所以贪心的查找,另一边有就往另一边找,没有只好走下去。
F - Perfect Security
由于前面的字典序都小了,那么后面的再大也赶不上。
所以考虑贪心,把 P 数组加入 Trie,每次查找完就删掉。
G - Forbidden Prefix
方法一:其实如果有了一个前缀 \(X\) 插入到了字典树里面,那么字数内所有的 \(Y\) 都挂了。
所以直接打上标记,下次不在访问即可。
方法二:同样的,如果访问到了一个 \(X\),就打上标记,然后字数内就不访问了。
类似线段树,每次类似 pushup 的时候可以合并每个子树的信息,如果有标记就清空。
H - Edit to Match
注意到,插入后直接判断是长度还是剩下的乘二更小就好了。
I - Dr. Evil Underscores
具体来说,如果全部都在左边,就递归左子树。
如果都在右边,就递归右子树。
如果两边看起来都可以,就分别递归。
诶,时间复杂度不会爆炸吗?
因为深度最大 \(\log n\) 层,所以复杂度不会爆。
J - A Lot of Games
分三种情况讨论
- 后手能必胜,那么后手如果一直赢就赢了。
- 先手能必胜,且可以必输,那么先手如果一直输到最后一次赢就可以了。
- 先手必胜但不能保证必输,那么每次都赢然后交换位置。\(k\) 为奇数时先手赢,反之后手赢。

浙公网安备 33010602011771号