Codeforces Round #430 (Div. 2)

题目链接:http://codeforces.com/contest/842/problem/D

题意:定义Mex为一个序列中最小的未出现的正整数,给定一个长度为n的序列,然后有m个询问,每个询问给定一个数x,先对序列每个数与x进行异或运算(^),之后输出当前序列修改完之后的Mex。

思路:因为对于原序列和x异或后,得到的新序列再与y异或相当于原序列与z(z=x^y)进行异或,所以问题就可以转化为对于一个数val,原序列和val进行异或后得到新序列的Mex是多少? 考虑01字典树,先把序列的n个数插入字典树(相同的数只插一次),考虑现在的val=0,那么如果左子树(边权为0的边)没有满,说明Mex在左子树,否则在右子树,直到最后到叶子结点为止,那么答案就是该叶子所代表的权值。  现在考虑val为任意数,对于val的二进制为0的位,按照上面的分析即可,但是对于二进制为1的位,优先走右子树(边权为1的边,因为1^1=0, 1^0=1,所以对于右子树相当于异或后的左子树, 左子树相当于异或后的右子树), 一直到叶子结点为止。  

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<time.h>
#include<cmath>
#include<sstream>
#include<assert.h>
using namespace std;
typedef long long int LL;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
const int MAXN = 3e5 + 24;
struct Trie{
    int val[MAXN << 4];
    int next[MAXN << 4][2];
    int root, L;
    int newnode(){
        next[L][0] = next[L][1] = -1;  val[L] = 0;
        return L++;
    }
    void init(){
        L = 0; root = newnode(); build(0,0);
    }
    void build(int u,int deep){
        if (deep == 19){
            return;
        }
        next[u][0] = newnode(); 
        next[u][1] = newnode();
        build(next[u][0], deep + 1);
        build(next[u][1], deep + 1);
    }
    void insert(int x){
        int now = root;
        for (int i = 18; i >= 0; i--){
            int num = (1 << i)&x ? 1 : 0;
            now = next[now][num];
            val[now]++;
        }
    }
    int Query(int x){
        int now = root, res = 0;
        for (int i = 18; i >= 0; i--){
            int num = (1 << i)&x ? 1 : 0;
            if (val[next[now][num]] < (1 << i)){ //异或后0的边
                now = next[now][num];
            }
            else{ //异或后1的边, 顺便把权值累计
                now = next[now][!num];
                res |= (1 << i);
            }
        }
        return res;
    }
}trie;
set<int>se;
int main(){
#ifdef kirito
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int start = clock();
    int n, m,val;
    while (~scanf("%d%d", &n, &m)){
        int prexor = 0;
        trie.init(); se.clear();
        for (int i = 1; i <= n; i++){
            scanf("%d", &val);
            if (!se.count(val)){
                trie.insert(val);
            }
            se.insert(val);
        }
        for (int i = 1; i <= m; i++){
            scanf("%d", &val);
            prexor ^= val;
            printf("%d
", trie.Query(prexor));
        }
    }
#ifdef LOCAL_TIME
    cout << "[Finished in " << clock() - start << " ms]" << endl;
#endif
    return 0;
}
原文地址:https://www.cnblogs.com/kirito520/p/7452412.html