[CodeForces948D]Perfect Security(01字典树)

题目链接:D. Perfect Security
题目大意:给定一个数组,要从另外一个数组中找到依次找到一个数,是它和数组对应的值的异或值最小。
题目思路:标准的01字典树,其中涉及字典树的构建,添加,查找和删除,可以作为一个典型的字典树模板题。
个人理解,如果字典树是26叉树,那么01字典树就是2叉树。
先上代码,在代码里面解释:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define bit(x) x&(-x)
using namespace std;
const int maxn =3e5+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll n;
ll a[maxn];  
ll s[maxn*32][2];   //s数组是建立的树;
ll v[maxn*32],sum[maxn*32][2]; //v数组用来标记在该点是否有插入的值,sum标记树的每一个点在建树的时候被遍历了几次。
ll to=0;
void unit()
{
    memset(s,0,sizeof(s));  //对数组进行清零
    memset(v,0,sizeof(v));
    memset(sum,0,sizeof(sum));
}
void add(ll w)  //int最多位移31位,所以开为long long;
{
    int root=0;
    for(int i=32;i>=0;i--){
        int r=(w>>i)&1;
        if(!s[root][r]){
            s[root][r]=++to;
        }
         sum[root][r]++;  //在建树过程中把经历过的点都加一
         root=s[root][r];  //root相当于一个指针
    }
    v[root]=w;  //每录入完一个数,把他最后一个root的v数组的值加如x记录下来;
}
ll find(ll a)
{
    int root=0;  //这里在查找的时候就进行了删除
    for(int i=32;i>=0;i--){
        int id=(a>>i)&1;
        if(sum[root][id]){  //只有在建树的时候被遍历过的点才可以选;贪心的选取最小的
            sum[root][id]--;
            root=s[root][((a>>i)&1)];
        }
        else{
            sum[root][id^1]--;  //表示这个值已经被找到了,把该值删去。
            root=s[root][((a>>i)&1)^1];
        }
    }
    //cout<<v[root]<<endl;
    return v[root];
}
int main()
{
    while(~scanf("%lld",&n)){
        unit();
        to=0;
        for(ll i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        for(ll i=1;i<=n;i++){
            ll k;
            scanf("%lld",&k);
            add(k);
        }
        for(ll i=1;i<=n;i++){
            printf("%lld\n",a[i]^find(a[i]));
        }
    }
    return 0;
}

下面是把查找和删除分开处理的代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define bit(x) x&(-x)
using namespace std;
const int maxn =3e5+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll n;
ll a[maxn];
ll s[maxn*32][2];
ll v[maxn*32],sum[maxn*32][2];
ll to=0;
void unit()
{
    memset(s,0,sizeof(s));
    memset(v,0,sizeof(v));
    memset(sum,0,sizeof(sum));
}
void add(ll w)
{
    int root=0;
    for(int i=32;i>=0;i--){
        int r=(w>>i)&1;
        if(!s[root][r]){
            s[root][r]=++to;
        }
         sum[root][r]++;
         root=s[root][r];
    }
    v[root]=w;
}
ll find(ll a)
{
    int root=0;
    for(int i=32;i>=0;i--){
        int id=(a>>i)&1;
        if(sum[root][id]){
            root=s[root][((a>>i)&1)];
        }
        else{
            root=s[root][((a>>i)&1)^1];
        }
    }
    //cout<<v[root]<<endl;
    return v[root];
}
void del(ll a)
{
    int root=0;
    for(int i=32;i>=0;i--){
        int id=(a>>i)&1;
        sum[root][id]--;
        root=s[root][id];
    }
    //v[root]=0;
}
int main()
{
    while(~scanf("%lld",&n)){
        unit();
        to=0;
        for(ll i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        for(ll i=1;i<=n;i++){
            ll k;
            scanf("%lld",&k);
            add(k);
        }
        for(ll i=1;i<=n;i++){
            printf("%lld\n",a[i]^find(a[i]));
            del(find(a[i]));
        }
    }
    return 0;
}
发布了35 篇原创文章 · 获赞 25 · 访问量 832

猜你喜欢

转载自blog.csdn.net/qq_43816599/article/details/97548133