题意
给你一个序列,有次操作,每次询问给你一个数,将序列所有数异或上。每次求序列中没有出现过的最小非负整数。
分析
在别人的博客里学到,如果没有异或操作。那么求题目中的只需要用权值线段树上二分就好了。每次走到线段树的某个节点时,看一下左儿子存在的数是不是等于左儿子对应的值域大小,就是看一下左儿子是不是满的。然而加上了异或就明显不能维护了。
所以这个时候就又到了我们树表演了,上二分查,并且走到上某个点时,如果异或的数这一位为,意义就是交换的左右儿子,然后就可以用和线段树一样的方法做了。
代码
#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; }