01字典树模板

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;
}



猜你喜欢

转载自blog.csdn.net/u013852115/article/details/80095309