传送门
解析:
卡了我好久。。。明明是一个裸的 01 T R I E 01TRIE 01TRIE。。。
思路:
显然由于修改只有 x o r xor xor操作,所以我们可以方便的把所有数插入一个 01 T R I E 01TRIE 01TRIE,并且维护一个全局 x o r t a g xortag xortag,这样就可以随时知道任何数当前值。
对于询问 m e x mex mex,我们直接在 T R I E TRIE TRIE树上带着 x o r t a g xortag xortag跑,尽可能向 x o r xor xor后的0儿子跑,跑到满的节点就直接向另一个儿子走,这样能够保证总是跑到一个合法的,并且尽可能的小的点。
最后,如果是动态开点的 T R I E TRIE TRIE树,请注意走到空节点的情况,我就是这样被卡的。
不明白为什么其他人建了权值线段树,(反正没我的
01
T
r
i
e
01Trie
01Trie快)
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline void outint(int a){
static char ch[13];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=300005;
struct _01TRIE{
int son[N*21][2];
int siz[N*21];
int tot;
int xortag;
void insert(int x){
int now=0;
for(int re i=20;~i;--i){
bool f=x&(1<<i);
if(!son[now][f])son[now][f]=++tot;
now=son[now][f];
++siz[now];
}
}
int query(){
int now=0,ans=0;
for(int re i=20;~i;--i){
bool f=xortag&(1<<i);
if(!son[now][f])return ans;
if(siz[son[now][f]]==(1<<i)){
ans|=1<<i;
now=son[now][!f];
}
else now=son[now][f];
}
return ans;
}
}Trie;
bool vis[N];
int n,m;
signed main(){
n=getint();
m=getint();
for(int re i=1;i<=n;++i){
int x=getint();
if(!vis[x])vis[x]=true,Trie.insert(x);
}
while(m--){
int x=getint();
Trie.xortag^=x;
outint(Trie.query());pc('\n');
}
return 0;
}