Vitya and Strange Lesson CodeForces - 842D 字典树+交换节点

题意:

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

Input
2 2
1 3
1
3
Output
1
0
Input
4 3
0 1 5 6
1
2
4
Output
2
0
0
Input
5 4
0 1 5 6 7
1
1
4
5
Output
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 }

猜你喜欢

转载自www.cnblogs.com/kongbursi-2292702937/p/12001509.html