01字典树
01字典树和普通字典树区别在于01字典树存的只有0和1;看到这里显然想到了二进制;
没错,01字典树主要是求异或最大(小)值;
把每个数分解成0和1的二进制存在树中;然后贪心的找要求的那个数对应的二进制位不同的点;
可能太抽象了,看代码应该就能看懂;
先引出一道模板题;
代码:
#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.其他和字典树大同小异;
本文深入探讨01字典树的基本概念与应用,重点讲解如何利用01字典树求解异或最大值问题。通过实例代码解析,展示01字典树在二进制运算中的优势及其实现细节。
4236

被折叠的 条评论
为什么被折叠?



