HDU 4825 Xor Sum 01字典树应用

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值