数据结构专题 - 解题报告 - O

按位异或,将数字转化为二进制数字,按位比较,如果不相等则为1,相等则为0。做法是建立一颗01trie,在字典树上贪心查找,从高位到地位,最大值是相同的位上选不同的数字,最小值则是在同一位上尽可能选择相同的数字。
插入:化为二进制表示就是从最高位向下排列,依次搭入主树干,如果有出现过的节点,就在数该节点出现次数cnt[now]++,之后也方便删除操作。在树枝末端存下该树枝表示的数字,查询方便调用。
删除:沿着二进制表示的树枝依次将其出现次数cnt[now] - - ,如果修改后此时cnt[now]==0则说明这条树枝已经没了,之后查询也不会走这条路。
查询:树上贪心,如果有想要的值存在就选,不在就被迫选另一解即可,最后得到选择的数字与目标数字异或计算输出。

#include<bits/stdc++.h>
#define maxn 500005
#define maxm 10000005
#define FOR(a, b, c) for(int a=b; a<=c; a++)
#define hrdg 1000000007
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define pi acos(-1.0)
#define ls p<<1
#define rs p<<1|1
using namespace std;

int ch[maxn<<5][2];
ll value[maxn<<5];
int node_cnt=1;
int cnt[maxn<<5];
int n, type;
ll v;

inline ll read()
{
    char c=getchar();long long x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}

void Insert(ll x)
{
    int now = 0;
    cnt[now]++;
    for(int i=32; i>=0; i--)
    {
        int idx = (x>>i)&1;         //节点值,0或1
        if(!ch[now][idx])           //如果该节点没有存在过
        {
            ch[now][idx] = node_cnt;        //新建节点枝叶
            value[node_cnt++] = 0;        //没有到达底端的节点代表值都为0
        }
        now = ch[now][idx];
        cnt[now] ++;        //节点个数计数,后面可能会删除
    }
    value[now] = x;     //x插入最后一位,之后每一次查询都会查到叶子末端,找到对应值
}
void Delete(ll x)
{
    int now = 0;
    cnt[now]--;
    for(int i=32; i>=0; i--)
    {
        int idx = (x>>i)&1;
        now = ch[now][idx];
        cnt[now]--;
    }
}
ll query1(ll x)
{
    int now = 0;
    for(int i=32; i>=0; i--)
    {
        int idx = (x>>i)&1;
        if(ch[now][idx^1] && cnt[ch[now][idx^1]])       //异或最大,指能不一样就不一样,贪心
            now = ch[now][idx^1];
        else
            now = ch[now][idx];
    }
    return value[now];
}
ll query2(ll x)
{
    int now = 0;
    for(int i=32; i>=0; i--)
    {
        int idx = (x>>i)&1;
        if(ch[now][idx] && cnt[ch[now][idx]])        //优先选取相同的节点
            now = ch[now][idx];
        else
            now = ch[now][idx^1];
    }
    return value[now];
}
int main()
{
    n = read();
    FOR(i, 1, n)
    {
        type = read(); v = read();
        if(type == 1)
            Insert(v);
        if(type == 2)
            Delete(v);
        if(type == 3)
            printf("%lld %lld\n", v^query2(v), v^query1(v));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值