按位异或,将数字转化为二进制数字,按位比较,如果不相等则为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;
}