01字典树学习笔记

mac2025-12-28  7

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.其他和字典树大同小异;

最新回复(0)