题意

给你一个序列,有次操作,每次询问给你一个数,将序列所有数异或上。每次求序列中没有出现过的最小非负整数。

分析

在别人的博客里学到,如果没有异或操作。那么求题目中的只需要用权值线段树上二分就好了。每次走到线段树的某个节点时,看一下左儿子存在的数是不是等于左儿子对应的值域大小,就是看一下左儿子是不是满的。然而加上了异或就明显不能维护了。
所以这个时候就又到了我们树表演了,上二分查,并且走到上某个点时,如果异或的数这一位为,意义就是交换的左右儿子,然后就可以用和线段树一样的方法做了。

代码

#include<bits/stdc++.h>
#define ll long long
const int N=1e7+5,INF=0x3f3f3f3f,mod=998244353,limit=18;
using namespace std;

int n,m,cnt=1,py,x;
int tr[N][2],siz[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}

int qpow(int a,int b)
{
    int ans=1;
    while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
    return ans;
}

void insert(int x,int u=1,int now=limit)
{
    if(now==-1) return siz[u]=1,void();
    int s=x>>now&1;
    if(!tr[u][s]) tr[u][s]=++cnt;
    insert(x,tr[u][s],now-1);
    siz[u]=siz[tr[u][0]]+siz[tr[u][1]];
}

int query(int x=py)
{
    int u=1,res=0;
    for(int i=limit;i>=0;--i)
    {
        int s=x>>i&1;
        if(siz[tr[u][s]]==((1<<i))) u=tr[u][s^1],res|=(1<<i);
        else u=tr[u][s];
        if(!u) return res;
    }
    return res;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)
        x=read(),insert(x);
    while(m--)
    {
        x=read();py^=x;
        printf("%d\n",query());
    }
    return 0;
}