题意:
给你一个长度为n的数组,然后有m次询问,每次询问有一个值x,让数组的每一个值异或x后,求数组中不存在的最小非负整数。
思路:
先将数组中的元素按01trie树建立, 然后每一次查询查询相当于原数组和(当前的值和前面次数的值异或)异或。
01trie树上找答案:
如果与当前位异或为0的点不存在则输出当前结果。
如果与当前位异或为0的点为根的子树满了则往异或为1找,如果还不存在则加上该位的值再输出结果。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[33], cnt[9200005][2], ji=1;
int pa[300005], f[9200005];
ll pb[300005];
void Insert()
{
int now=0, i=31;
while(i>=0)
{
if(cnt[now][a[i]]==-1)
{
cnt[now][a[i]]=ji;
ji++;
}
now=cnt[now][a[i]];
i--;
}
}
int dfs(int v,int d)
{
if(d==31)
{
f[v]=1;
return 1;
}
if(cnt[v][0]!=-1)
{
dfs(cnt[v][0],d+1);
}
if(cnt[v][1]!=-1)
{
dfs(cnt[v][1],d+1);
}
if(f[cnt[v][1]]&&f[cnt[v][0]])
{
f[v]=1;
return 1;
}
return 0;
}
ll fun()
{
ll now=0, p=0, i=31, k=(1LL<<31);
while(i>=0)
{
if(a[i]==1)
{
if(cnt[now][1]!=-1&&f[cnt[now][1]]!=1)
{
now=cnt[now][1];
}
else if(cnt[now][1]==-1)
{
return p;
}
else if(cnt[now][0]!=-1&&f[cnt[now][0]]!=1)
{
p=p+k;
now=cnt[now][0];
}
else if(cnt[now][0]==-1)
{
return p+k;
}
}
else
{
if(cnt[now][0]!=-1&&f[cnt[now][0]]!=1)
{
now=cnt[now][0];
}
else if(cnt[now][0]==-1)
{
return p;
}
else if(cnt[now][1]!=-1&&f[cnt[now][1]]!=1)
{
p=p+k;
now=cnt[now][1];
}
else if(cnt[now][1]==-1)
{
return p+k;
}
}
i--;
k=k/2;
}
return p;
}
int main()
{
int n, m;
scanf("%d%d",&n,&m);
memset(cnt,-1,sizeof(cnt));
for(int i=0;i<n;i++)
{
scanf("%d",&pa[i]);
int x=pa[i], j=0;
memset(a,0,sizeof(a));
while(x)
{
a[j++]=x%2;
x=x/2;
}
Insert();
}
dfs(0,-1);
for(int i=0;i<m;i++)
{
scanf("%lld",&pb[i]);
if(i!=0)
{
pb[i]=(pb[i]^pb[i-1]);
}
ll x=pb[i], j=0;
memset(a,0,sizeof(a));
while(x)
{
a[j++]=x%2;
x=x/2;
}
cout << fun() << endl;
}
return 0;
}

京公网安备 11010502036488号