HDU 4825 Xor Sum
01字典树:字典树的一种,所存元素只有0,1,是求那种给出一组数,再给一个数,然后找出异或以后最大的数,这种问题的解决方法
题目大意
给出一个包含n个数的集合,随后m次发问,给出一个数s,在所给的数的集合中找一个k,使得s与k的异或的结果是最大的。
输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。
Sample Input2
3 2
3 4 5
1
5
4 1
4 6 5 6
3
Sample OutputCase #1:
4
3
Case #2:
4
解题思路
1.首先,因为是找最大的,所以用01字典树存的时候要从高位开始存起,所以建树的时候有一个技巧就是循环从23才开始向右移动以后,再与1与一下,就可以取那一位
2.然后存入树里面,定义一个val数组,记录结束结点位置时候,所存的数是多少。
3.查找的时候,同样的方法从高位开始分离出每一位,因为我们希望异或完了之后的结果是1,所以我们拿这位去与1异或就能得到要的。
4.然后如果有这节存在就走那一节,不然就走唯一的路,结束以后的节点用val数组看一下就可以得到我们要的结果。
5.其实是一个01字典树的模板应用。
解题代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
#include <bitset>
#define inf 0x3f3f3f3f
#define ll long long
#define ma 100004
#define mod 1000000007
using namespace std;
int tr[32*ma][2];
ll val[32*ma];
int tot;
void init()
{
memset(tr,0,sizeof(tr));
tot=1;
}
void creat(ll a)
{
int root=0;
for(int i=32;i>=0;i--)
{
int c=((a>>i)&1);
if(tr[root][c]==0)
{
val[tot]=0;
tr[root][c]=tot++;
}
root=tr[root][c];
}
val[root]=a;
}
ll sear(ll a)
{
int root=0;
for(int i=32;i>=0;i--)
{
int c=((a>>i)&1);
if(tr[root][c^1])
root=tr[root][c^1];
else
root=tr[root][c];
}
return val[root];
}
int main()
{
int t;
scanf("%d",&t);
for(int k=1;k<=t;k++)
{
init();
int n,m;
scanf("%d%d",&n,&m);
ll a,b;
for(int i=0;i<n;i++)
{
scanf("%lld",&a);
creat(a);
}
printf("Case #%d:\n",k);
for(int i=0;i<m;i++)
{
scanf("%lld",&b);
printf("%d\n",sear(b));
}
}
return 0;
}