01字典树是普通字典树的一种变形,主要用来处理两个数的最大异或值问题
现在可以先自己想想怎么把普通字典树变形成01字典树
- 普通字典树存储的字符,例如26个字母的字典树是26叉树,01字典树存储的是01,显然是二叉树
- 一颗存储int型的01字典树最多有32层(其中第一层类似于普通字典树是根结点,不存储任何内容)
- 01字典树其实就是将整型数据转换为二进制,数的叶节点存储着二进制的最低位,越靠近根节点,存储的位数越高。
解决最大异或,那么就贪心的找对应位不同的分支即可
例题 HDU4825
给你n个数,再给出m次询问,对于每次询问,给出一个值x,让你在n个数中找到一个数,与x异或值最大
那么我们先对n个数建树,每次询问就贪心的找即可。
tips:对于删树操作,应该可以用两种方式,第一种就是直接初始化所有数组,另一种可以只初始化根结点,在第二次创建的过程中进行初始化,可以针对删树操作的频繁程度进行选择。
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0);
#define ll long long
ll z_o_trie[32000000][2];
ll value[32000000];
ll cnt = 1;
void Insert(ll a)
{
ll p = 0;
for (ll i = 31; i >= 0; i--)
{
ll temp = (a >> i) & 1;
if (z_o_trie[p][temp])
p = z_o_trie[p][temp];
else
p = z_o_trie[p][temp] = cnt++;
}
value[p] = a;
}
ll get(ll a)
{
ll p = 0;
for (ll i = 31; i >= 0; i--)
{
ll temp = (a >> i) & 1;
if (z_o_trie[p][temp ^ 1])
p = z_o_trie[p][temp ^ 1];
else
p = z_o_trie[p][temp];
}
return value[p];
}
void init()
{
cnt = 1;
fill(z_o_trie[0], z_o_trie[0] + 1000000 * 2, 0);
fill(value, value + 1000000, 0);
}
int main()
{
IOS;
ll t;
cin >> t;
ll CASE = 1;
while (t--)
{
cout << "Case #" << CASE++ << ":" << endl;
init();
ll n, m;
cin >> n >> m;
for (ll i = 1; i <= n; i++)
{
ll temp;
cin >> temp;
Insert(temp);
}
for (ll i = 1; i <= m; i++)
{
ll temp;
cin >> temp;
cout << get(temp) << endl;
}
}
return 0;
}