码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforce842D Vitya and Strange Lesson

时间:2017-09-01 00:01:43      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:define   保留   str   name   names   scanf   题解   分解   div   

题意:一个序列(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;
}

 

Codeforce842D Vitya and Strange Lesson

标签:define   保留   str   name   names   scanf   题解   分解   div   

原文地址:http://www.cnblogs.com/Noevon/p/7460915.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!