图片说明
题目大意:
给你一个长度为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;
}