01字典树

余生长醉 提交于 2020-03-02 01:14:06

学习与:https://blog.csdn.net/zuzhiang/article/details/79872805

一.描述




1.与普通字典树相似,只不过不是插入字符,而是 插入二进制串的每一位(0或1)

2.01字典树是一棵最多32层的二叉树

3.tree[i] 表示一个节点,tree[i][0] 和 tree[i][1] 表示节点的两条边指向的节点,val[i] 表示节点的值。

4.每个节点主要有 4个属性: 节点值、节点编号、两条边指向的下一节点的编号。

5.节点值 val为 0 时表示到当前节点为止 不能形成一个数,否则 val[i]=数值。

6.可通过贪心的策略来寻找 与x异或结果最大(最小)的数 ,即 优先找和x的二进制的未处理的最高位值不同(相同)的边对应的点 ,这样保证结果最大。

二.模板

int tot=0;
ll val[32*maxn];
int tree[32*maxn][2];
 
void init()
{ //初始化 
    tot=0;
   memset(tree,0,sizeof(tree));
   memset(val,0,sizeof(val));
}
void insertt(ll num) //插入
{
    int root=0;
    for(int i=32;i>=0;i--)
    {
        int id=(num>>i)&1;
        if(!tree[root][id])
            tree[root][id]=++tot;
        root=tree[root][id];
        val[root]++;
    }
    val[root]=num; 
}
int query1(ll num)
{ //查询所有数中和num异或结果最大的数
    int root=0;
    for(int i=32;i>=0;i--){
        int id=(num>>i)&1;
        if(tree[root][id^1]) //优先走和当前位不同的路
            root=tree[root][id^1];
        else root=tree[root][id];
    }
    return val[root];///返回与该数异或值最大的那个数,不是异或结果!!!
}
int query2(int num)
{ //查询所有数中和num异或结果最小的数
    int root=0;
    for(int i=32;i>=0;i--){
        int id=(num>>i)&1;
        if(tree[root][id]) //优先走和当前位相同的路
            root=tree[root][id];
        else root=tree[root][id^1];
    }
    return val[root];
}

应用:

HDU 4825

给出n个数和m次询问,每次询问给出一个数x,问在n个数中哪个数与x异或值最大?

代码

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn =1e6+5;
int tot=0;
ll val[3*maxn];
int tree[3*maxn][2];

void init()
{ //初始化
    tot=0;
   memset(tree,0,sizeof(tree));
   memset(val,0,sizeof(val));
}
void insertt(ll num) //插入
{
    int root=0;
    for(int i=32;i>=0;i--)
    {
        int id=(num>>i)&1;
        if(!tree[root][id])
            tree[root][id]=++tot;
        root=tree[root][id];
        val[root]++;
    }
    val[root]=num;
}
ll findd(ll num)
{ //查询所有数中和num异或结果最大的数
    int root=0;
    for(int i=32;i>=0;i--){
        int id=(num>>i)&1;
        if(tree[root][id^1]) //优先走和当前位不同的路
            root=tree[root][id^1];
        else root=tree[root][id];
    }
    return val[root];
}
int main()
{
    int t;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        int n,m,p;
        scanf("%d%d",&n,&m);
        init();
        for(int j=0;j<n;j++)
        {
            scanf("%d",&p);
            insertt(p);
        }
        printf("Case #%d:\n",i);
        for(int j=0;j<m;j++)
        {
            scanf("%d",&p);
            printf("%d\n",findd(p));
        }
    }
    return 0;
}


csu 1216
与上一题差不多,只是输出的是,这些数中两个数的异或值最大的那个值

代码:

for(int j=0;j<n;j++)
        {
            mmax=max(mmax,a[j]^findd(a[j]));
        }
        printf("%d\n",mmax);
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!