01字典树常用来处理XOR问题。本质是把一个数字转换成二进制,然后建一颗字典树。这颗字典树上的所有元素只有0或者1…
模板题
题意,给一个数组,再给数字。找这个数字xor数组中的元素的最大值
二进制下不同的位数越多,异或的结果越大
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define ll long long
#define lowbit(x) (x&(-x))
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=998424353;
const int maxn=1E5+10;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
int tree[32*maxn][2];
int val[32*maxn];
int tot=0;
void insert(ll x){
int root=0;
for (int i=32;i>=0;i--){
int id=(x>>i)&1;
if (!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
val[root]=x;
}
ll query (ll x){
int root=0;
for (int i=32;i>=0;i--){
int id=(x>>i)&1;
if (tree[root][id^1]) root=tree[root][id^1];//二进制下不同的位数越多,异或的结果越大
else root=tree[root][id];
}
return val[root];
}
int main (){
int t;int m,n;ll tmp;
scanf ("%d",&t);for (int turn=1;turn<=t;turn++){
MT(tree,0);
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++){
scanf("%lld",&tmp);
insert(tmp);
}
printf("Case #%d:\n",turn);
while (n--){
scanf("%lld",&tmp);
printf("%lld\n",query(tmp));
}
}
return 0;
还是例题
题意,给两个等长数组,分别取一个元素异或,求最后异或的结果最小。每个元素用一次。
在上题的基础上,需要标记使用过的元素。我的标记方式是,insert的时候增加vis,query的时候减少vis。判断vis的正负。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define ll long long
#define lowbit(x) (x&(-x))
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=998424353;
const int maxn=3E5+10;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
int tree[32*maxn][2];
int val[32*maxn];
int num[32*maxn];
int vis[32*maxn];
int tot=0;
void insert(ll x){
int root=0;
for (int i=32;i>=0;i--){
int id=(x>>i)&1;
if (!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
vis[root]++;
}
val[root]=x;
}
int query (int x){
int root=0;
for (int i=32;i>=0;i--){
int id=(x>>i)&1;
if (tree[root][id]&&vis[tree[root][id]]>0){
root=tree[root][id];
}
else root=tree[root][id^1];
vis[root]--;
}
return val[root];
}
int main (){
int n,tmp;
while (~scanf ("%d",&n)){
tot=0;
MT(tree,0);
MT(vis,0);
for (int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
for (int i=1;i<=n;i++){
scanf("%d",&tmp);
insert(tmp);
}
for (int i=1;i<=n;i++){
printf("%d",num[i]^query(num[i]));
if (i!=n) printf(" ");
else printf("\n");
}
}
return 0;
}