CF842D Vitya and Strange Lesson

题意简述

(n)个数(a_1,a_2,cdots,a_n),有(m)个操作,每次操作给一个数(x),要求:

  • 将所有数(operatorname{xor} space x)
  • 求此时数列的( ext{mex})
    ( ext{mex})指当前数列未出现的最小非负整数。
    数据范围自行查看题目。

简单口胡

先考虑一下没有第一个(operatorname{xor})操作的时候怎么做。我们将所有数插入一个01-trie中,对于每一位我们都想:最好往0走。但是什么时候是不能往0走的呢?
如果左子树(即0节点的子树)是一个满二叉树,说明如果走到0节点,那么就没有不出现的数了,而我们要找的是( ext{mex}),违背定义,这时候只能退而求其次,走1节点。

加上了(operatorname{xor})其实也是差不多的,异或具有结合律,即(a operatorname{xor} x_1 operatorname{xor} x_2 = a operatorname{xor} (x_1 operatorname{xor} x_2)),所以记录(s)为当前的(operatorname{xor})和,如果第(i)(s)为1,那么就是说明01-trie的第(i)层要取反,那么也就是最好往1走,如果是0那就是一样的。

写的话还是看水平,反正我写了好久/kk

# include <bits/stdc++.h>
using namespace std;

const int N = 3e5 + 5;

int n,m;

int a[N];

int s;

struct _01trie
{
    int T[N << 2][2],siz[N << 2];
    int tot = 0;

    void insert(int x)
    {
        int root = 0;
        for(int i = 20; i >= 0; i--)
        {
            int p = (x >> i) & 1;
            if(T[root][p] == 0) T[root][p] = ++tot;
            root = T[root][p];
        }
        return;
    }
    void dfs(int root)
    {
        
        if(T[root][0] == 0 && T[root][1] == 0) 
        {
            siz[root] = 1;
            return;
        }
        if(T[root][0]) dfs(T[root][0]);
        if(T[root][1]) dfs(T[root][1]);
        siz[root] += siz[T[root][0]] + siz[T[root][1]] + 1;
        // printf("root = %d,siz[%d] = %d
",root,root,siz[root]);
        return;
    }
    int query(void)
    {
        int root = 0;
        int ans = 0;
        for(int i = 20; i >= 0; i--)
        {
            int p = (s >> i) & 1;
            // if(p == 1) 
            // {
            //     printf("i = %d
",i);
            //     printf("root = %d
",root);
            //     printf("T = %d
",T[root][p]);
            //     printf("siz = %d
",siz[T[root][p]]);
            // }
            if(T[root][p] != 0 && siz[T[root][p]] == (1 << (i + 1)) - 1) 
            {
                // printf("root = %d
",root);
                root = T[root][p ^ 1],ans += (1 << i);
            
            }
            else root = T[root][p];
            if(!root) break;
        }
        return ans;
    }
}Trie;

int main(void)
{   
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
    sort(a + 1,a + n + 1);
    int Newn = unique(a + 1,a + n + 1) - a - 1;
    for(int i = 1; i <= Newn; i++) 
    {
        Trie.insert(a[i]);
    }
    Trie.dfs(0);
    while(m--)
    {
        int x;
        scanf("%d",&x);
        s ^= x;
        printf("%d
",Trie.query());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/luyiming123blog/p/14350334.html