01字典树(两道模板题)

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;
}
发布了33 篇原创文章 · 获赞 15 · 访问量 907

猜你喜欢

转载自blog.csdn.net/weixin_43925900/article/details/97888054
今日推荐