01字典树

01字典树主要就是来解决异或求最值的问题,利用字典树的建树方式然后在查询的时候使用贪心的思想求最值。

关于字典树可以参考这篇博客:字典树

01字典树是按位插入和查询的。因为如果一个数,它的高位值较大,那么这个数的值较大。所以我们插入和查询时是从最高位开始进行的。同时可以开val数组来保存每个值。

01字典树和普通的字典树原理类似,只不过把插入字符改成了插入二进制串的每一位(0或1)。

1. 01字典树是一棵最多 32层的二叉树,其每个节点的两条边分别表示二进制的某一位的值为 0 还是为 1. 将某个路径上边的值连起来就得到一个二进制串。

2.节点个数为 1 的层(最高层)节点的边对应着二进制串的最高位。

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

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

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

6.可通过贪心的策略来寻找与 x异或结果最大的数,即优先找和 x二进制的未处理的最高位值不同的边对应的点,这样保证结果最大。
主要思想看代码:

Code:

const ll inf=0x3f3f3f3f;
int tol; //节点个数
const int MAXN = 100010;
ll val[32*MAXN]; //点的值
int tree[32*MAXN][2]; //边的值
int n,m;
int i,j,k;
ll q;
ll a[100010];
ll ans,res,temp;
void init()
{
    //初始化
    tol=1;
    tree[0][0]=tree[0][1]=0;
}

void add(ll x)
{
    //往 01字典树中插入 x
    int u=0;
    for(int i=32; i>=0; i--)
    {
        int v=(x>>i)&1;//二进制下的第i位
        if(!tree[u][v])
        {
            //如果节点未被访问过
            tree[tol][0]=tree[tol][1]=0; //将当前节点的边值初始化
            val[tol]=0; //节点值为0,表示到此不是一个数
            tree[u][v]=tol++; //边指向的节点编号
        }
        u=tree[u][v]; //下一节点
    }
    val[u]=x; //节点值为 x,即到此是一个数
}

ll query(ll x)
{
    //查询所有数中和 x异或结果最大的数
    int u=0;
    for(int i=32; i>=0; i--)
    {
        int v=(x>>i)&1;//二进制下的第i位
        //利用贪心策略,优先寻找和当前位不同的数
        if(tree[u][v^1])
            u=tree[u][v^1];
        else
            u=tree[u][v];
    }
    return val[u]; //返回结果
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值