题意:
给你一个长度为n的数组,然后有m次询问,每次询问有一个值x,让数组的每一个值异或x后,求数组中不存在的最小非负整数。
思路:
先将数组中的元素按01trie树建立, 然后每一次查询查询相当于原数组和(当前的值和前面次数的值异或)异或。
01trie树上找答案:
如果与当前位异或为0的点不存在则输出当前结果。
如果与当前位异或为0的点为根的子树满了则往异或为1找,如果还不存在则加上该位的值再输出结果。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int a[33], cnt[9200005][2], ji=1; int pa[300005], f[9200005]; ll pb[300005]; void Insert() { int now=0, i=31; while(i>=0) { if(cnt[now][a[i]]==-1) { cnt[now][a[i]]=ji; ji++; } now=cnt[now][a[i]]; i--; } } int dfs(int v,int d) { if(d==31) { f[v]=1; return 1; } if(cnt[v][0]!=-1) { dfs(cnt[v][0],d+1); } if(cnt[v][1]!=-1) { dfs(cnt[v][1],d+1); } if(f[cnt[v][1]]&&f[cnt[v][0]]) { f[v]=1; return 1; } return 0; } ll fun() { ll now=0, p=0, i=31, k=(1LL<<31); while(i>=0) { if(a[i]==1) { if(cnt[now][1]!=-1&&f[cnt[now][1]]!=1) { now=cnt[now][1]; } else if(cnt[now][1]==-1) { return p; } else if(cnt[now][0]!=-1&&f[cnt[now][0]]!=1) { p=p+k; now=cnt[now][0]; } else if(cnt[now][0]==-1) { return p+k; } } else { if(cnt[now][0]!=-1&&f[cnt[now][0]]!=1) { now=cnt[now][0]; } else if(cnt[now][0]==-1) { return p; } else if(cnt[now][1]!=-1&&f[cnt[now][1]]!=1) { p=p+k; now=cnt[now][1]; } else if(cnt[now][1]==-1) { return p+k; } } i--; k=k/2; } return p; } int main() { int n, m; scanf("%d%d",&n,&m); memset(cnt,-1,sizeof(cnt)); for(int i=0;i<n;i++) { scanf("%d",&pa[i]); int x=pa[i], j=0; memset(a,0,sizeof(a)); while(x) { a[j++]=x%2; x=x/2; } Insert(); } dfs(0,-1); for(int i=0;i<m;i++) { scanf("%lld",&pb[i]); if(i!=0) { pb[i]=(pb[i]^pb[i-1]); } ll x=pb[i], j=0; memset(a,0,sizeof(a)); while(x) { a[j++]=x%2; x=x/2; } cout << fun() << endl; } return 0; }