题意:一个序列(n<3e5),m个查询,每次序列所有的数亦或x,问这个序列的mex(mex定义是最小没有出现过的非负整数),保留每一次的更改
题解:首先要知道mex怎么求,把每一个数分解为二进制,按高位到低位进行建一颗二叉树,可以o(logn)查询到mex
其次要知道异或有结合率,也就是求一个前缀就可以了
分解每次查询的数,从高位到低位遍历,遍历到该为为bit,判断sum[(t<<1)+bit]这棵树有没有装满,装满的话就答案就在另一棵树
#include <bits/stdc++.h> #define ll long long #define maxn 300100 int a[maxn], n, m, sum[1<<20]; using namespace std; void build(){ for(int i=0;i<n;i++){ bitset<19>bit(a[i]); int t = 1; for(int i=18;i>=0;i--){ if(bit[i] == 0) t = t*2; else t =t*2+1; } sum[t] = 1; } for(int i=(1<<20)-1;i>=1;i--) sum[i>>1] += sum[i]; } int query(int temp){ bitset<19>bit(temp); int t = 1, ans = 0, cnt; for(int i=18;i>=0;i--){ cnt = (1<<i); ans = ans*2; if(bit[i] == 0){ if(sum[t<<1] == cnt) t = t<<1|1, ans++; else t = t<<1; } else{ if(sum[t<<1|1] == cnt) t = t<<1, ans++; else t = t<<1|1; } } return ans; } int main(){ scanf("%d%d", &n, &m); for(int i=0;i<n;i++) scanf("%d", &a[i]); build(); int temp = 0; while(m--){ scanf("%d", &n); temp ^= n; printf("%d\n", query(temp)); } return 0; }
时间: 2024-10-03 14:55:51