【hdu4825】xor sum

之前在网上找trie树关于异或的题目,首先很少,其次多是bzoj的权限题,像我这样的穷苦人家的oier用不起qwq,正当准备洗洗睡了的时候,偶然看到了这个题,还算是一个比较好的练习23333333

这个题利用trie树来快速查找一个与s异或值最大的数,因为异或是两位如果不一样就返回1,因此我们需要尽可能的让这两个数的每一位不一样,因此当s的某一位为0的时候,我们就尽可能走1,反之则尽可能走0。利用trie树可以灰常简单的进行查找,时间复杂度是O(len),len不会超过32,所以查找灰常快,就是建树慢。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int t,n,ro,m,p;
long long mi[60],a;
struct in
{
    int l,r;
    long long v;
    void clear()
    {
        l=r=-1;
    }
}ter[5500000];
void insert(int &ro,int d,long long u)//尽可能的找一位位答案与s不同的 
{
    if(ro==-1)
        ro=p++,ter[ro].clear();//如果这里为-1,申请一个节点 
    if(d==-1)
    {
        ter[ro].v=u;return;//如果到头头了,返回 
    }
    if(u&mi[d])//向右建树 
        insert(ter[ro].r,d-1,u);
    else//向左 
        insert(ter[ro].l,d-1,u);
}
void ask(int ro,int d,int u)
{
    if(d==-1)//如果到了存储答案的地方 
    {
        printf("%lld\n",ter[ro].v);
        return;
    }
    if(((u&mi[d])&&ter[ro].l!=-1)||ter[ro].r==-1)//如果这个数这一位上是1且左蛾子能走,或者是右蛾子不能走 
        ask(ter[ro].l,d-1,u);//就向左走 
    else
        ask(ter[ro].r,d-1,u);//否则向右走 
}
int main()
{
    scanf("%d",&t);
    mi[0]=1;
    for(int i=1;i<55;i++)
        mi[i]=mi[i-1]*2;//预处理到2^54 
    for(int i=1;i<=t;i++)
    {
        p=0,ro=-1;//p是节点个数,ro是上一次的根 
        scanf("%d%d",&n,&m);
        for(int j=1;j<=n;j++)
            scanf("%lld",&a),insert(ro,50,a);//插入 
        printf("Case #%d:\n",i);
        for(int j=1;j<=m;j++)
            scanf("%lld",&a),ask(ro,50,a);//查询答案 
    }
}

 

posted @ 2017-10-23 07:00  那一抹落日的橙  阅读(147)  评论(0编辑  收藏  举报