题意
n个数,m个操作,对于每一个操作
- 首先给出一个数 x , 每一个 a [ i ] 更新为与 x 按位异或的结果
- 求出这 n 个数的 Mex
分析
- 首先这 m 个操作的 x 是可以重合在一起的,也就是说,并不用每输入一次 x 就将数组更新
- 求Mex:这个Mex是在数组中最小的没有出现过的数,联想我们已经建立的trie树,如果没有异或操作,只询问 Mex那其实就是在 trie 上找最靠左的一个空位。那这个呢?不就是带了个x呗。尽量走一条与x按位异或结果相同的道路。很明显,因为这个数要不存在,说明节点下方的子节点不能将空位全部占满,否则只能走另一条路。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,m,tot=1;
int tr[2][N*10],siz[N*10];
inline void ins(int x,int i,int &rt)
{
if(i==-1)
{
siz[rt]=1;
return ;
}//计算有多少个叶子节点
bool c=((x>>i)&1);
if(!tr[c][rt]) tr[c][rt]=++tot;
ins(x,i-1,tr[c][rt]);
siz[rt]=siz[tr[0][rt]]+siz[tr[1][rt]];
}
inline int find(int now)
{
int ans=0,rt=1;
for (int i=18;i>=0;i--)
{
bool c=((now>>i)&1);
if(!rt) return ans;
if(siz[tr[c][rt]]==(1<<i))
ans+=(1<<i),rt=tr[c^1][rt];
else rt=tr[c][rt];
}
return ans;
}
int main()
{
memset(tr,0,sizeof(tr));
scanf("%d%d",&n,&m);
for (int i=1,x,rt;i<=n;i++)
{
scanf("%d",&x);
rt=1;ins(x,18,rt);
}
//应该有多少节点
int x,now=-1;
while(m--)
{
scanf("%d",&x);
if(now==-1) now=x;else now^=x;
printf("%d\n",find(now));
}
return 0;
}
京公网安备 11010502036488号