题目大意:
给你一个长度为n的序列,和m个操作,每个操作包含两部分:
1)对序列(a1,a2,...,an) ^ x
2)找出序列的。
思路:
如果按照题目要求去做,我们需要对字典树有修改,查询的操作。
但是字典树好像没修改操作。(应该是我不会修改)。
但是异或满足结合律,即 (a1,a2,a3,a4,..,an) ^ x ^ y ^ .. ^ z = (a1,a2,a3,a4,..,an) ^ (x ^ y ^ .. ^ z)
这样对于m个询问我们可以用一个变量来存询问的前缀异或值,这样就可以不对字典树进行修改操作了。
但是第二个问题是函数怎么求呢?
当我们把插入字典树mex函数的值应该是除了这些数的其他数,所以我们可以只需要将不是序列的数插入字典树,然后用前缀异或值去找最小值就是答案了。
参考:
https://blog.nowcoder.net/n/e0e7f512f59e4f6f8972ac959748ff70
https://blog.nowcoder.net/n/0c329efa6ca544d78eaa498912713e3e
代码:
#include<iostream> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 2e7 + 10; typedef long long int ll; int trie[maxn][2],tot; bool vis[maxn]; void insert(int x){ int p = 0; for(int i = 30; i >= 0; i--){ int c = (x >> i) & 1; if(!trie[p][c])trie[p][c] = ++tot; p = trie[p][c]; } } int query(int x){ int p = 0,res = 0; for(int i = 30; i >= 0; i--){ int c = (x >> i) & 1; if(trie[p][c])p = trie[p][c]; else p = trie[p][c ^ 1],res |= (1 << i); } return res; } void solved(){ int n,m;cin>>n>>m; for(int i = 1; i <= n; i++){ int x;cin>>x;vis[x] = 1; } for(int i = 0; i <= 600010; i++) if(!vis[i])insert(i); int temp = 0; for(int i = 1; i <= m; i++){ int x;cin>>x;temp = temp ^ x; printf("%d\n",query(temp)); } } int main(){ solved(); return 0; }