01字典树在异或问题的查询上十分高效。
01字典树是按位插入和查询的。因为如果一个数,它的高位值较大,那么这个数的值较大。所以我们插入和查询时是从最高位开始进行的。
可以开一个辅助数组val来记录原数值。
插入:
#define ll long long
int n,m;
int trie[32*MAXN][2];
ll val[32*MAXN];
int tot;
void insert(ll d)
{
int root=0;
for(int i=32;i>=0;i--)
{
int id=(d>>i)&1;//获得这一个bit位的值
if(!trie[root][id]) trie[root][id]=++tot;
root=trie[root][id];
}
val[root]=d;
}
查询:
ll query(ll d)
{
int root=0;
for(int i=32;i>=0;i--)
{
int id=(d>>i)&1;
if(trie[root][id^1]) root=trie[root][id^1];
else root=trie[root][id];
}
return val[root];
}
例题:HDU - 4825
给出一个S,在数组里找到一个数K,使得K^S最大。
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define ll long long
int n,m;
int trie[32*MAXN][2];
ll val[32*MAXN];
int tot;
void insert(ll d)
{
int root=0;
for(int i=32;i>=0;i--)
{
int id=(d>>i)&1;//获得这一个bit位的值
if(!trie[root][id]) trie[root][id]=++tot;
root=trie[root][id];
}
val[root]=d;
}
ll query(ll d)
{
int root=0;
for(int i=32;i>=0;i--)
{
int id=(d>>i)&1;
if(trie[root][id^1]) root=trie[root][id^1];
else root=trie[root][id];
}
return val[root];
}
int main()
{
int cas;
scanf("%d",&cas);
for(int tt=1;tt<=cas;tt++)
{
scanf("%d%d",&n,&m);
memset(trie,0,sizeof trie);
for(int i=0;i<n;i++)
{
int d;
scanf("%d",&d);
insert(d);
}
printf("Case #%d:\n",tt);
for(int i=0;i<m;i++)
{
ll d;
scanf("%lld",&d);
printf("%lld\n",query(d));
}
}
return 0;
}