Author has gone out of the stories about Vasiliy, so here is just a formal task description.
You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries:
- "+ x" — add integer x to multiset A.
- "- x" — erase one occurrence of integer x from multiset A. It's guaranteed that at least one x is present in the multiset A before this query.
- "? x" — you are given integer x and need to compute the value
, i.e. the maximum value of bitwise exclusive OR (also know as XOR) of integer x and some integer y from the multiset A.
Multiset is a set, where equal elements are allowed.
Input
The first line of the input contains a single integer q (1 ≤ q ≤ 200 000) — the number of queries Vasiliy has to perform.
Each of the following q lines of the input contains one of three characters '+', '-' or '?' and an integer xi (1 ≤ xi ≤ 109). It's guaranteed that there is at least one query of the third type.
Note, that the integer 0 will always be present in the set A.
OutputFor each query of the type '?' print one integer — the maximum value of bitwise exclusive OR (XOR) of integer xi and some integer from the multiset A.
Example10 + 8 + 9 + 11 + 6 + 1 ? 3 - 8 ? 3 ? 8 ? 11
11 10 14 13
After first five operations multiset A contains integers 0, 8, 9, 11, 6 and 1.
The answer for the sixth query is integer — maximum among integers
,
,
,
and
.
题意:有一个集合,初始时只有0,三种操作+ x:意思是往集合中加入x,- x:从集合中删除x,? x:询问x与集合中的所有数字的最大异或值。需要明确的一点是,若向集合中添加了两个数字x,然后删除了一个x,那么此时集合中还是存在一个x的。
思路:同样的是一道01字典树,只是多了一个删除操作,我们只需再开一个二维数组将每个数字是否存在统计一下即可。详细请看代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const int mod=1e9+7;
const double pi=acos(-1);
const double eps=1e-8;
const int N=2e5+10;
int trie[N*32][2],tot;
int sum[N*32][2];//统计二进制位是否存在,为0是表示不存在,>0存在
void sert(int x,int y)
{
int root=0;
for(int i=31;i>=0;i--)
{
int id=(x>>i)&1;
sum[root][id]+=y;
if(!trie[root][id]) trie[root][id]=++tot;
root=trie[root][id];
}
}
void finf(int x)
{
int root=0,ans=0;
for(int i=31;i>=0;i--)
{
int id=(x>>i)&1^1;
if(trie[root][id]&&sum[root][id]) ans+=1<<i;
else id^=1;
root=trie[root][id];
}
printf("%d\n",ans);
}
char s[2];
int main()
{
int t,n;
sert(0,1);
scanf("%d",&t);
while(t--)
{
mem(s,0);
scanf("%s%d",s,&n);
if(s[0]=='+') sert(n,1);
else if(s[0]=='-') sert(n,-1);
else finf(n);
}
}没用位运算的代码:#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const int mod=1e9+7;
const double pi=acos(-1);
const double eps=1e-8;
const int N=2e5+10;
int trie[N*32][2],tot,s[33],ans[33];
int sum[N*32][2];
void sert(int x)
{
int root=0;
for(int i=31;i>=0;i--)
{
int id=s[i];
sum[root][id]+=x;
if(!trie[root][id])
trie[root][id]=++tot;
root=trie[root][id];
}
}
void finf(int x)
{
int root=0,k=0;
for(int i=31;i>=0;i--)
{
int id=s[i];
if(trie[root][id^1]&&sum[root][id^1])
{
ans[k++]=id^1;
root=trie[root][id^1];
}
else
{
ans[k++]=id;
root=trie[root][id];
}
}
int tmp=0,t=1;
for(int i=31;i>=0;i--)
{
tmp+=ans[i]*t;
t*=2;
}
printf("%d\n",tmp^x);
}
char ss[2];
int main()
{
int t,n;
mem(s,0);
sert(1);
scanf("%d",&t);
while(t--)
{
mem(s,0);
scanf("%s%d",ss,&n);
int k=0,tt=n;
while(n)
{
s[k++]=n%2;
n>>=1;
}
if(ss[0]=='+') sert(1);
else if(ss[0]=='-') sert(-1);
else finf(tt);
}
}

本文介绍了一种使用01字典树解决带有增删操作的最大异或值查询问题的方法,通过维护一个能记录元素存在状态的字典树来高效处理各种查询。
253

被折叠的 条评论
为什么被折叠?



