+ a代表把a加入字典
- a代表把b移出字典
? a要求输出字典中与a异或最大的
思路:
套路神似,保留所有的二进制位数,从高位开始去寻找相反的,贪心找最高位,答案会最大
注意cnt的问题,因为我们要保证当前这个是字典中某个数的二进制数 而不是 二进制数的前缀. 所以,我们全部cnt++. 在query的时候,如果p->next==NULL,说明根本没出现过.如果p->cnt==0说明出现过,但是已经被删完了,下面全都是空的.
假如,我们的cnt++放在最后.而不是对于所有前缀进行cnt++.那么会发生什么问题呢?对于很多节点我们的cnt都是0,无法得知下面到底有没有.那么在p->[t]还是p->[1-t]就无法判断.出错. 对于每个节点cnt++,这样就完美地联系了前缀和完整二进制的关系.
#include <stdio.h>
#include <malloc.h>
#include <iostream>
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define bug1 cout << "bug1" << endl
#define bug2 cout << "bug2" << endl
#define bug3 cout << "bug3" << endl
#define bug4 cout << "bug4" << endl
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int MAX_N=1e5+5;
struct node{
node *next[2];
int cnt;
node(){
cnt=0;
next[0]=next[1]=NULL;
}
};
node *root;
void buildtrie(ll x){
node *p=root;
for(int i=1;i<=32;i++){
int t=(x>>(32-i))&1;
// if(x==11)cout <<"t="<<t<<" i="<<i<<endl;
if(!p->next[t]) p->next[t]=new node();
p=p->next[t];
p->cnt++;
}
return ;
}
void del(ll x){
node *p=root;
for(int i=1;i<=32;i++){
int t=(x>>(32-i))&1;
p=p->next[t];p->cnt--;
// cout <<"bit="<<33-i<<" p->cnt="<< p->cnt << endl;
}
return ;
}
ll query(ll x){
node *p=root;
ll sum=0;
for(int i=1;i<=32;i++){
int t=(x>>(32-i))&1;
if(!p->next[1-t] || !p->next[1-t]->cnt) p=p->next[t];
else{
sum+=1<<(32-i);
p=p->next[1-t];
// cout <<"need="<<1-t<<"bit="<<33-i<<" p->cnt="<< p->cnt << endl;
}
}
return sum;
}
int main(void){
int t;
root=new node();
buildtrie(0);
cin >> t;
for(int i=1;i<=t;i++){
char op[2];
ll num;
scanf("%s",op+1);
scanf("%I64d",&num);
if(op[1]=='+') buildtrie(num);
else if(op[1]=='-') del(num);
else if(op[1]=='?') printf("%I64d\n",query(num));
}
return 0;
}
/*
*/