HDU4825_01字典树

01字典树是普通字典树的一种变形,主要用来处理两个数的最大异或值问题

现在可以先自己想想怎么把普通字典树变形成01字典树

  • 普通字典树存储的字符,例如26个字母的字典树是26叉树,01字典树存储的是01,显然是二叉树
  • 一颗存储int型的01字典树最多有32层(其中第一层类似于普通字典树是根结点,不存储任何内容)
  • 01字典树其实就是将整型数据转换为二进制,数的叶节点存储着二进制的最低位,越靠近根节点,存储的位数越高。

解决最大异或,那么就贪心的找对应位不同的分支即可

例题 HDU4825
给你n个数,再给出m次询问,对于每次询问,给出一个值x,让你在n个数中找到一个数,与x异或值最大

那么我们先对n个数建树,每次询问就贪心的找即可。

tips:对于删树操作,应该可以用两种方式,第一种就是直接初始化所有数组,另一种可以只初始化根结点,在第二次创建的过程中进行初始化,可以针对删树操作的频繁程度进行选择。

AC代码:

#include 
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;
}

你可能感兴趣的:(2020暑假集训打卡,#,字典树)