题意:求一个给定n个数组,求下标范围在l和r的数组是否每一个数组都能表示x。
线性基求交。
注意查询时不需要对线性基进行合并。
#include <bits/stdc++.h>
#define lc l,mid,x<<1
#define rc mid+1,r,x<<1|1
using namespace std;
typedef long long LL;
const int maxn = 50005;
const int base = 32;
template <typename T>
struct node
{
T a[base+1]; //线性基的插入结果
void init(){
memset( a,0,sizeof(a) );
}
bool ins(T b) // 向线性基中插入一个数
{
for(int i=base;i>=0;i--)
if(b>>i){
if(!a[i])
{
a[i]=b;
return true ;
}
b^=a[i];
}
return false ;
}
bool check (T b) // 如果可以表示出来,返回true ,否则返回 false
{
for(int i=base;i>=0;i--)
{
if(b>>i)
{
if(!a[i])return false ;
b^=a[i];
}
}
return true ;
}
};
node<LL>tree[maxn*4],tmp,v1;
template <typename T>
void merge(node<T> &ans,const node<T> &a1,const node<T> &a2 ) // 求 a1,a2的线性基,结果为 ans
{
tmp=v1 =a1;
T x,now;
for(int i=base;i>=0;i--)
{
if(!a2.a[i])continue;
x = a2.a[i],now=0;
int flag =1 ;
for(int j=base;j>=0;j--)
{
if(x>>j)
{
if(!tmp.a[j])
{
flag =0,tmp.a[j]=x,v1.a[j]=now;
break;
}
x^=tmp.a[j],now^=v1.a[j];
}
}
if(flag)ans.ins(now);
}
}
void push_up( int x ){
merge( tree[x],tree[x<<1],tree[x<<1|1] );
}
void build( int l,int r,int x ){
if( l == r ){
int sz;LL v;
scanf("%d",&sz);
for( int i = 0;i < sz;i++ ){
scanf("%lld",&v);
tree[x].ins(v);
}
return;
}
int mid = l+r>>1;
build(lc);
build(rc);
push_up(x);
}
node<LL> res,c,re;
bool query( int left,int right,LL v,int l,int r,int x ){
if( left <= l && right >= r ){
return tree[x].check(v);
}
int mid = l+r>>1;
if( right > mid&&!query(left,right,v,rc) ) return 0;// = query(left,right,rc);
if( left <= mid && !query(left,right,v,lc) )return 0;// = query(left,right,lc);
return 1;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
build( 1,n,1 );
for( int i = 1;i <= m;i++ ){
LL x;
int l,r;
scanf("%d%d%lld",&l,&r,&x);
bool flag = query( l,r,x,1,n,1 );
if(!flag ){
puts("NO");
}else{
puts("YES");
};
}
return 0;
}