对于每一个数,我们找出他的最高位的 1 在第 i 位, 如果此时 Pi 为零,就将这个数加入线性基,否则异或 Pi 继续找。然后我们就可以在 0 到 k 位上处理好每一位的线性基。这样得到的线性基保证每一位都能有对应的最大值。
void get_p(LL x)
{
for(int i=62;i>=0;i--)
{
if((x>>(LL)i))
{
if(!p[i])
{
p[i]=x;
break;
}
x^=p[i];
}
}
}
在我们得到的线性基中,从高位到低位用贪心贪掉每一个元素,如果异或了这个元素变大就异或他。
LL ans=0;
for(int i=62;i>=0;i--)
if((ans^p[i])>ans)ans^=p[i];
我们也是从低到高扫这个数的每一位,如果这第 i 位为 1,就异或上 Pi,然后知道处理到最后一位。如果变成 0 了,那么就是可以的。
bool check(int x)//查询能否异或成某个数
{
for(int i=31;i>=0;i--)
{
if(x>>i)x^=p[i];
}
return x==0;
}
有一道模板题,不过要用到线段树来优化查询
题目链接:https://ac.nowcoder.com/acm/contest/884/B
#include<bits/stdc++.h>
using namespace std;
const int maxx=5e4+10;
int a[maxx<<2][32];
void insert(int x,int temp)//构造线性基
{
for(int i=31;i>=0;i--)
{
if(x>>i)
{
if(!a[temp][i])
{
a[temp][i]=x;
break;
}
x^=a[temp][i];
}
}
}
bool check(int x,int temp)//查询能否异或成某个数
{
for(int i=31;i>=0;i--)
{
if(x>>i)x^=a[temp][i];
}
return x==0;
}
void pushup(int temp)//线性基求交
{
int t1[32],t2[32],l=temp*2,r=temp*2+1;
for(int i=0;i<32;i++)
t1[i]=t2[i]=a[l][i];
for(int i=0;i<32;i++)
{
if(a[r][i])
{
int x=a[r][i],t=0;
for(int j=31;j>=0;j--)
{
if(x>>j)
{
if(!t1[j])
{
t1[j]=x,t2[j]=t;
break;
}
x^=t1[j],t^=t2[j];
}
}
if(!x)insert(t,temp);
}
}
}
void build(int l,int r,int temp)
{
if(l==r)
{
int s,t;
scanf("%d",&s);
while(s--)
{
scanf("%d",&t);
insert(t,temp);
}
return;
}
int mid=(l+r)/2;
build(l,mid,temp*2);
build(mid+1,r,temp*2+1);
pushup(temp);
}
bool query(int l,int r,int p,int q,int x,int temp)
{
if(p<=l&&r<=q)
{
return check(x,temp);
}
int mid=(l+r)/2;
bool res=1;
if(p<=mid)res&=query(l,mid,p,q,x,temp*2);
if(q>mid)res&=query(mid+1,r,p,q,x,temp*2+1);
return res;
}
int main()
{
int n,m;
cin>>n>>m;
build(1,n,1);
int p,q,x;
while(m--)
{
scanf("%d%d%d",&p,&q,&x);
if(query(1,n,p,q,x,1))printf("YES\n");
else printf("NO\n");
}
return 0;
}
原文:https://www.cnblogs.com/HooYing/p/11349578.html