01 trie
前言
引用一句刘邦的话:“有时 01 Trie
胜于 01 Trie
。”
正文
前景提要
- Trie(串串咕了 qwq)
- 位运算
- 贪心
01 trie
简介
实质上是字符集只有
由于每一个自然数一定可以进行二进制拆分,所以一个数其实可以看成一个二进制下的 01 串。
所以 01 trie 是可以高效维护序列上的位运算问题的。
另外由于 01 trie 维护的字符串实质上是二进制拆分后的一个数,其长度为
代码解析
01 trie 不同于其它 ds,其运作主要是基于贪心实现的,并且要求选手对二进制又一定的熟悉程度。
下面以 CF923C 为例,对 01 trie 的代码进行解析。
CF923C
- 分析
1.题目要求让
2.此时题目转化为异或最小值问题,可以考虑使用 01 trie
3.倘若我们考虑完第
- 代码解析
const int V = 31; // 表示维护的值域拆成二进制下的最高位数
int tot; // 01 trie 上节点总数
struct Trie {
int sz // 可以用来维护诸如 trie 树上的子树和之类的东西,此处并未用到
, cnt // 维护到当前节点的前缀的出现次数
, ch[2]; // 字符集,01 trie 的字符集就是 0/1
inline int operator [] (const bool x) const { // 个人代码习惯重载
return ch[x];
}
} t[N << 5]; // 保险起见未限制空间时开 5 倍空间
inline void insert(int x) {
int p = 0; // 当前节点
for(int i = V - 1 ; ~ i ; -- i) {
bool w = x & (1 << i); // 要插入的数字从高往低的二进制位
if(! t[p][w]) t[p].ch[w] = ++ tot; // 若此前没有节点则新建
p = t[p][w], ++ t[p].cnt; // 迭代节点,统计前缀出现次数
}
}
// 基本上 01 trie 的入门题变化就出现在查询时的贪心考虑
inline int query(int x) {
int p = 0, res = 0; // 当前节点与使得与 x 异或值最小的答案
for(int i = V - 1 ; ~ i ; -- i) {
bool w = x & (1 << i);
if(! t[t[p][w]].cnt) w ^= 1; // 贪心,尽量要让二进制下两位相同异或和才能小,若不同才选择另外一个
res = (res << 1) | w; // 统计答案
p = t[p][w];
-- t[p].cnt; // 查询时顺便删除
}
return res ^ x; // 记得异或 x
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!