学习与:https://blog.csdn.net/zuzhiang/article/details/79872805
一.描述
1.与普通字典树相似,只不过不是插入字符,而是 插入二进制串的每一位(0或1)
2.01字典树是一棵最多32层的二叉树
3.tree[i] 表示一个节点,tree[i][0] 和 tree[i][1] 表示节点的两条边指向的节点,val[i] 表示节点的值。
4.每个节点主要有 4个属性: 节点值、节点编号、两条边指向的下一节点的编号。
5.节点值 val为 0 时表示到当前节点为止 不能形成一个数,否则 val[i]=数值。
6.可通过贪心的策略来寻找 与x异或结果最大(最小)的数 ,即 优先找和x的二进制的未处理的最高位值不同(相同)的边对应的点 ,这样保证结果最大。
二.模板
int tot=0;
ll val[32*maxn];
int tree[32*maxn][2];
void init()
{ //初始化
tot=0;
memset(tree,0,sizeof(tree));
memset(val,0,sizeof(val));
}
void insertt(ll num) //插入
{
int root=0;
for(int i=32;i>=0;i--)
{
int id=(num>>i)&1;
if(!tree[root][id])
tree[root][id]=++tot;
root=tree[root][id];
val[root]++;
}
val[root]=num;
}
int query1(ll num)
{ //查询所有数中和num异或结果最大的数
int root=0;
for(int i=32;i>=0;i--){
int id=(num>>i)&1;
if(tree[root][id^1]) //优先走和当前位不同的路
root=tree[root][id^1];
else root=tree[root][id];
}
return val[root];///返回与该数异或值最大的那个数,不是异或结果!!!
}
int query2(int num)
{ //查询所有数中和num异或结果最小的数
int root=0;
for(int i=32;i>=0;i--){
int id=(num>>i)&1;
if(tree[root][id]) //优先走和当前位相同的路
root=tree[root][id];
else root=tree[root][id^1];
}
return val[root];
}
应用:
HDU 4825
给出n个数和m次询问,每次询问给出一个数x,问在n个数中哪个数与x异或值最大?
代码
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn =1e6+5;
int tot=0;
ll val[3*maxn];
int tree[3*maxn][2];
void init()
{ //初始化
tot=0;
memset(tree,0,sizeof(tree));
memset(val,0,sizeof(val));
}
void insertt(ll num) //插入
{
int root=0;
for(int i=32;i>=0;i--)
{
int id=(num>>i)&1;
if(!tree[root][id])
tree[root][id]=++tot;
root=tree[root][id];
val[root]++;
}
val[root]=num;
}
ll findd(ll num)
{ //查询所有数中和num异或结果最大的数
int root=0;
for(int i=32;i>=0;i--){
int id=(num>>i)&1;
if(tree[root][id^1]) //优先走和当前位不同的路
root=tree[root][id^1];
else root=tree[root][id];
}
return val[root];
}
int main()
{
int t;
cin>>t;
for(int i=1;i<=t;i++)
{
int n,m,p;
scanf("%d%d",&n,&m);
init();
for(int j=0;j<n;j++)
{
scanf("%d",&p);
insertt(p);
}
printf("Case #%d:\n",i);
for(int j=0;j<m;j++)
{
scanf("%d",&p);
printf("%d\n",findd(p));
}
}
return 0;
}
csu 1216
与上一题差不多,只是输出的是,这些数中两个数的异或值最大的那个值
代码:
for(int j=0;j<n;j++)
{
mmax=max(mmax,a[j]^findd(a[j]));
}
printf("%d\n",mmax);
来源:CSDN
作者:夷则九
链接:https://blog.csdn.net/weixin_45719073/article/details/104564703