codeforces 842 D. Vitya and Strange Lesson(01字典树+思维+贪心)

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

题解:像这种求一段异或什么的都可以考虑用字典树而且mex显然可以利用贪心+01字典树,和线段树差不多就是比较节点总数和有的数字数比较有限向左边转移。

然后这个异或其实可以利用一个数num与一个一个的x异或然后求异或的mex也是容易的只要判断当前二进制位是1那么左右节点拥有的数字数互换(不用真的互换

只要用转移体现出来就行了)。这里的01字典树写法是类似线段树且利用递归的方法。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int M = 2e5 + 10;
int ch[20 * M][2] , nodes[20 * M];
int node_size , num;
void build(int pos , int node) {
    if(pos < 0) return;
    for(int i = 0 ; i < 2 ; i++) {
        ch[node][i] = ++node_size;
        nodes[node_size] = 0;
        build(pos - 1 , ch[node][i]);
    }
}
void init() {
    node_size = 0;
    nodes[0] = 0;
    build(19 , 0);
}
void Insert(int node , int x , int pos) {
    if(pos < 0) {
        nodes[node] = 1;
        return ;
    }
    int id = (x >> pos) & 1;
    Insert(ch[node][id] , x , pos - 1);
    nodes[node] = nodes[ch[node][id]] + nodes[ch[node][id ^ 1]];
}
int query(int node , int x , int pos) {
    if(pos < 0) return x;
    int gg = (num >> pos) & 1;
    if(nodes[ch[node][gg]] < (1 << pos)) return query(ch[node][gg] , x , pos - 1);
    return query(ch[node][gg ^ 1] , x | (1 << pos) , pos - 1);
}
int main() {
    int n , m , x;
    num = 0;
    init();
    scanf("%d%d" , &n , &m);
    for(int i = 0 ; i < n ; i++) {
        scanf("%d" , &x);
        Insert(0 , x , 19);
    }
    for(int i = 0 ; i < m ; i++) {
        scanf("%d" , &x);
        num ^= x;
        printf("%d
" , query(0 , 0 , 19));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/7513807.html