题意:
Today at the lesson Vitya learned a very interesting function — mex. Mex of a sequence of numbers is the minimum non-negative number that is not present in the sequence as element. For example, mex([4, 33, 0, 1, 1, 5]) = 2 and mex([1, 2, 3]) = 0.
Vitya quickly understood all tasks of the teacher, but can you do the same?
You are given an array consisting of n non-negative integers, and m queries. Each query is characterized by one number x and consists of the following consecutive steps:
- Perform the bitwise addition operation modulo 2 (xor) of each array element with the number x.
- Find mex of the resulting array.
Note that after each query the array changes.
Input
First line contains two integer numbers n and m (1 ≤ n, m ≤ 3·105) — number of elements in array and number of queries.
Next line contains n integer numbers ai (0 ≤ ai ≤ 3·105) — elements of then array.
Each of next m lines contains query — one integer number x (0 ≤ x ≤ 3·105).
Output
For each query print the answer on a separate line.
Examples
2 2
1 3
1
3
1
0
4 3
0 1 5 6
1
2
4
2
0
0
5 4
0 1 5 6 7
1
1
4
5
2
2
0
2
题意:
找出来这n个数中没有的最小自然数
之后有m次对数组的处理(设m行每行输入的数为x),让数组里面的所有数都和x异或。然后输出这n个数中没有的最小自然数
注释+代码:
1 /* 2 将所有的数字以二进制的方式插入到 trie 树中,然后我们便可以很方便的求出一个序列的 mex 值。 3 假如要全局异或一个数 x ,且 x 的二进制从高到低第 i 位是 1 ,则 trie 树中的第 i 层所有节点都要翻转左右孩子。 4 5 为什么遇到1要翻转,遇到0不需要? 6 如果是0的话,那么原来数是0,异或之后结果还是0;如果原来数是1,异或之后结果还是1 7 8 并且x^y^z=x^(y^z) 9 */ 10 #include <iostream> 11 #include <cstdio> 12 #include <cstring> 13 #include <cstdlib> 14 #include <algorithm> 15 using namespace std; 16 typedef long long ll; 17 const int maxn=20; 18 const int mod=998244353; 19 const int N=3e5+10; 20 typedef struct Trie* TrieNode; 21 int v[N]; 22 struct Trie 23 { 24 int val,sum; 25 TrieNode next[2]; 26 Trie() 27 { 28 val=0; 29 sum=0; 30 memset(next,NULL,sizeof(next)); 31 } 32 }; 33 void inserts(TrieNode root,int x) 34 { 35 TrieNode p = root; 36 for(int i=maxn;i>=0;--i) 37 { 38 int temp=(x>>i)&1; 39 if(p->next[temp]==NULL) p->next[temp]=new struct Trie();//printf("*%d*",temp); 40 //p->next[temp]->sum+=1; 41 p=p->next[temp]; 42 p->sum+=1; 43 } 44 } 45 void update(TrieNode p,int x) 46 { 47 for(int i=0;i<2;++i) 48 if(p->next[i]!=NULL) 49 p->next[i]->val^=p->val; //这个p->next[i]->val为什么要异或? 50 if((p->val>>x)&1) //因为我们每一次只能走字典树的一个方向,所以另一个方向是没有异或过这个x的,所以报 51 swap(p->next[0],p->next[1]); //保留下来,和线段树的懒惰标记差不多 52 p->val=0; 53 } 54 void query(TrieNode root,int x) 55 { 56 int ans=0; 57 TrieNode p=root; 58 for(int i=maxn;i>=0;i--) 59 { 60 update(p,i); 61 if(p->next[0]==NULL || p->next[0]->sum!=(1<<i)) //(1<<i)代表另一个树枝上所有数都存在时的个数 62 p=p->next[0]; //因为咱们时从二进制数的高位枚举到低位,所以遇到能走的零就要走 63 else p=p->next[1],ans|=1<<i; 64 if(p==NULL) break; 65 } 66 printf("%d\n",ans); 67 } 68 void Del(TrieNode root) 69 { 70 for(ll i=0 ; i<2 ; ++i) 71 { 72 if(root->next[i])Del(root->next[i]); 73 } 74 delete(root); 75 } 76 int main() 77 { 78 int n,m; 79 scanf("%d%d",&n,&m); 80 for(int i=0;i<n;++i) 81 scanf("%d",&v[i]); 82 sort(v,v+n); 83 TrieNode root=new struct Trie(); 84 inserts(root,v[0]); 85 for(int i=1;i<n;++i) 86 { 87 if(v[i]!=v[i-1]) 88 inserts(root,v[i]); 89 } 90 while(m--) 91 { 92 int x; 93 scanf("%d",&x); 94 root->val=x; //每一次都要 95 query(root,x); 96 } 97 Del(root); 98 return 0; 99 }