Vitya and Strange Lesson

Today at the lesson Vitya learned a very interesting function — mex. Mex of a sequence of numbers is the minimum non-negative number that is not present in the sequence as element. For example, mex([4, 33, 0, 1, 1, 5]) = 2 and mex([1, 2, 3]) = 0.

Vitya quickly understood all tasks of the teacher, but can you do the same?

You are given an array consisting of n non-negative integers, and m queries. Each query is characterized by one number x and consists of the following consecutive steps:

Perform the bitwise addition operation modulo 2 (xor) of each array element with the number x.
Find mex of the resulting array.
Note that after each query the array changes.

Input
First line contains two integer numbers n and m (1 ≤ n, m ≤ 3·105) — number of elements in array and number of queries.

Next line contains n integer numbers ai (0 ≤ ai ≤ 3·105) — elements of then array.

Each of next m lines contains query — one integer number x (0 ≤ x ≤ 3·105).

Output
For each query print the answer on a separate line.

Examples
input
2 2
1 3
1
3
output
1
0
input
4 3
0 1 5 6
1
2
4
output
2
0
0
input
5 4
0 1 5 6 7
1
1
4
5
output
2
2
0
2

题意:告诉你一个序列,然后给你m个操作,每个操作就是把这个序列异或上x,然后再得出最小的没有在这个序列中出现的数。就是所谓的mex;

解题思路:题目让找出没有出现的数的最小值,那就把没有出现的数存到插入到字典树中,(因为每个数异或一个数得到的结果是不同的,所以把出现的数异或后找没出现的数的最小值,就相当于 把没出现的数异或后得到的最小值是一样的),所以就把没出现的数存入字典树,每次找异或后得到的值最小;注意这道题的数据范围(代码中有解释);

具体看代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#define inf 0x3f3f3f3f
using namespace std;
typedef __int64 ll;
const int N=2;
const int M=1010005;//标记数组开的空间
const int MA=20;

//这里要解释一下M为啥比30W大,虽然题目只是说最大3*10^5,转换成二进制后有20位,
//如果二十位全为1就有2^20-2,大约100W,所以对应的,标记数组应该开到101W,但是这道题开到60W就能AC

typedef struct Node
{
    int count;
    Node *Next[N];
    int val;
} Node;

Node * build()
{
    Node *node=(Node *)malloc(sizeof(Node));
    node->count=0;
    node->Next[0]=node->Next[1]=0;
    return node;
}

void change(int x,int a[])
{
    for(int i=0; i<MA; i++)
        a[i]=(x>>(MA-1-i))&1;
}

void tire_insert(Node *root,int a[],int t)
{
    Node *p=root;
    int i=0;
    for(i=0;i<MA;i++)
    {
        if(p->Next[a[i]]==NULL)
            p->Next[a[i]]=build();
        p=p->Next[a[i]];
        p->count++;
        if(i==MA-1)
            p->val=t;
    }
}

int found(Node *root,int a[])
{
    int i,ans=0;
    Node *p=root;
    for(i=0;i<MA;i++)
    {
        if(p->Next[a[i]]!=NULL)
            p=p->Next[a[i]];
        else
            p=p->Next[!a[i]];
    }
    return p->val;
}

int main()
{
    int n,m,mp[M];//把出现的数用mp标记
    while(~scanf("%d %d",&n,&m))
    {
        int a[MA],i,j,tmp,c;
        Node *root=build();
        memset(mp,0,sizeof(mp));
        for(i=0;i<n;i++)
        {
            scanf("%d",&tmp);
            mp[tmp]=1;
        }
        for(i=0;i<=M;i++)
        {
            if(mp[i]==0)
            {
                change(i,a);
                tire_insert(root,a,i);
            }
        }
        tmp=0;
        for(i=0;i<m;i++)
        {
            scanf("%d",&c);
            tmp^=c;
            change(tmp,a);
            printf("%d\n",found(root,a)^tmp);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值