01字典树学习笔记

本文深入探讨01字典树的基本概念与应用,重点讲解如何利用01字典树求解异或最大值问题。通过实例代码解析,展示01字典树在二进制运算中的优势及其实现细节。

01字典树

01字典树和普通字典树区别在于01字典树存的只有0和1;看到这里显然想到了二进制;

没错,01字典树主要是求异或最大(小)值;

把每个数分解成0和1的二进制存在树中;然后贪心的找要求的那个数对应的二进制位不同的点;

可能太抽象了,看代码应该就能看懂;

先引出一道模板题;

hdu4825

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
//ios::sync_with_stdio(false);
using namespace std;
const int N=100100;
const int M=200100;
const LL mod=2e9+7;
int rt;//根结点 
LL val[32*N];//价值数组 
int tr[32*N][2];//01树 
void init(){//初始化 
	rt=0;
	memset(val,0,sizeof(val));
	memset(tr,0,sizeof(val));
}
void insert(LL x){
	int k=0;
	for(int i=32;i>=0;i--){
		int d=(x>>i)&1;//提取x的二进制首位 
		if(!tr[k][d]) tr[k][d]=++rt;
		k=tr[k][d];//下一结点 
	}
	val[k]=x;//到这个结点的数是x 
}
LL search(LL x){
	int k=0;
	for(int i=32;i>=0;i--){
		int d=(x>>i)&1;
		if(tr[k][d^1]) k=tr[k][d^1];//优先贪心异或值不一样的点,如果是求最小,则这里相反
		else k=tr[k][d];
	}
	return val[k];
}
int main(){
	ios::sync_with_stdio(false);
	int t;
	cin>>t;
	int ans=0;
	while(t--){
		init();
		cout<<"Case #"<<++ans<<":"<<endl;
		int n,m;
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			LL x;
			cin>>x;
			insert(x);
		}
		for(int i=1;i<=m;i++){
			LL s;
			cin>>s;
			cout<<search(s)<<endl;
		}
	}
	return 0;
}

这里解释几个点;
1.一般 int 数都是2^31-1,所以i到31开始就行,但是这道题的数的范围2 ^32,所以要开longlong,并且 i 开到32;

2.这里的search函数,寻找一个异或最大的数,只要尽量找到每位不同的数就行;(如果是求最小值,则贪心找每位相同的数)展现了二进制运算的奇妙和优势;

3.其他和字典树大同小异;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值