Vasiliy’s Multiset
题目大意:
有三种类型的查询:
“+ x” - 添加一个整数 X。
“ - x” - 删除一次整数 X。它保证至少有一个 X 存在于查询前的集合中。
“?x” - 给定整数 X 并且需要计算该值和一个整数Y的按位异或(也称为XOR)的最大值
这是一个允许相等元素的集合。
解题思路:
如果没有删除的话就是字典树求异或和模板题了,而现在需要有删除操作,我们新开一个index数组记录一下已有的节点即可(不能开bool数组,因为集合中可能有重复元素),添加就+1,删除-1,查询的时候>=1才可以到达此节点。
一定要记得提前把 0插入倒树里并标记为1,insert(0,1),一开始忘了这个操作,然后wa了5次
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 200007;
int t[MAXN<<5][3],tot=1,index[MAXN<<5];
void insert(int x,int w){ //插入到字典树
int p=1;
for(int k=31;k>=0;k--){ //转换成01串
int ch=x>>k&1; // if(x&(1<<i)) ch=1; else ch=0;
if(!t[p][ch]){
t[p][ch]=++tot;
}
p=t[p][ch];
index[p]+=w;
}
}
int search(int x){
int p=1,ans=0;
for(int k=31;k>=0;k--){
int ch=x>>k&1;
if(index[t[p][ch^1]]){ //尽可能找不一样的,贪心思想
p=t[p][ch^1];
ans|=1<<k;
}else p=t[p][ch];
}
return ans;
}
int main(){
int n,m,T,w;
char op[2];
memset(t,0,sizeof t);
memset(index,0,sizeof index);
scanf("%d",&T);
insert(0,1); //////////////////////////////////////提前把0标记为1
for(int k=1;k<=T;k++){
scanf("%s%d",op,&n);
if(op[0]=='+') insert(n,1);
else if(op[0]=='-') insert(n,-1);
else printf("%d\n", search(n));
}
return 0;
}