题目链接:http://codeforces.com/problemset/problem/706/D
题意:
给出q个操作,操作有三种类型。
①往集合添加一个数(+ x)
②删除集合里的某个数(- x)
③询问集合里某个数与给定的数异或的最大值(? x)
分析:
字典树从根节点往叶节点依次存取二进制数的高位到低位,寻找异或最大值时,沿着与当前位相反的路径走。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<map>
#include<vector>
#include<set>
using namespace std;
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define INF ((1<<31)-1)
#define in(x) scanf("%d", &x)
#define lin(x) scanf("%I64d", &x)
#define out(x) printf("%d\n", x)
#define rep(i,a,b) for(int i=a; i<=(b); i++)
#define ll __int64
#define mem(a,b) memset(a, b, sizeof(a))
#define bug(x) cout<<#x<<" = "<<x<<"; "
#define N 205
#define nn printf("\n")
/**
数据范围1e9<2^30,最多从0位存到第30位
*/
struct A
{
int tim, son[2];
///tim:该节点出现几次
///son[i]:儿子i在树中的编号
void set0()
{
tim=0;
mem(son,0);///0表示不存在
}
}trie[8000000];
int ind;///树的编号,trie数组的下标
int pow2[35]; ///pow2=1,2,4,8,16...下标从0开始
///pow2[i]表示1后面有i个0
void init()
{
ind=1;///根节点
trie[1].set0();
pow2[0]=1;
rep(i,1,30)
pow2[i]=pow2[i-1]*2;
}
//删除数字num
void del(int num)
{
int root=1, x;
for(int i=30; i>=0; i--)
{
x=(num&pow2[i])?1:0;///取出该位
int fa=root;
root=trie[root].son[x];///得到傻儿子编号
trie[root].tim--;
if(trie[root].tim==0)///该儿子出现次数为0
{
trie[fa].son[x]=0;///父节点删掉该儿子
break;///删掉该儿子等于删掉该儿子的所有子节点
///因为只能通过该儿子的编号访问其子节点,然而儿子编号没了
///下一次赋给该儿子的编号又是一个新值
}
}
}
//添加数字num
void add(int num)
{
int root=1, x;
///分解num的每一位,从高到低
for(int i=30; i>=0; i--)
{
x=(num&pow2[i])?1:0;///取出该位
if(trie[root].son[x]==0)///傻儿子未出现过
{
ind++;
trie[root].son[x]=ind;///儿子编号赋为ind
trie[ind].set0();
}
root=trie[root].son[x];
trie[root].tim++;
}
}
//询问与num异或之后的最大数
int query(int num)
{
int root=1, x, ans=0;
for(int i=30; i>=0; i--)
{
x=(num&pow2[i])?1:0;///取出该位
int ez=trie[root].son[x^1];///与该位相反的儿子编号
if(ez && trie[ez].tim>0)
{
ans+=pow2[i];
root=ez;
}
else
root=trie[root].son[x];
}
return ans;
}
int main()
{
int q;
in(q);
init();
add(0);
while(q--)
{
char s[5];
int k;
scanf("%s %d",s,&k);
if(s[0]=='+')
add(k);
else if(s[0]=='-')
del(k);
else
printf("%d\n", query(k));
}
return 0;
}