原题: https://ac.nowcoder.com/acm/contest/884/B
题意:
给出n个集合,m个查询,每个查询 ( L , R , v a l ) (L,R,val) (L,R,val),询问区间 [ L , R ] [L,R] [L,R]中的所有集合是否可以通过集合内异或来表示 v a l val val。
解析:
异或表示显然就是线性基了,一个线性基是否可以表示一个数大家都会做,现在要求区间内所有线性基是否可以。
先来说一个很显然的东西,我们定义两个线性基的交为:两个基都可以表示的位。
我在之前讲过,线性基里面的每个基相当于二进制中的一个比特位,假设我第一个线性基可以表示 30 , 28 , 26 , 20 30,28,26,20 30,28,26,20,第二个 29 , 28 , 20 , 19 29,28,20,19 29,28,20,19,那么两个线性基的交就是 28 , 20 28,20 28,20。
那么这道题显然考察的就是线性基的交,我们只需要求出一个区间内所有线性基的交,再用这个线性基去判断即可。如果交可以表示,那么显然区间内的所有线性基都可以表示了。
这个过程可以用线段树去维护,每个节点存对应区间的所有线性基的交。
代码:
#include
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
struct linear_Bace;
typedef linear_Bace LB;
const int maxn=50000+9;
const int Len=33;
struct linear_Bace{
int a[Len];
int& operator [](int idx){
return a[idx];
}
int operator [](int idx)const{
return a[idx];
}
void insert(int val){
for(int i=Len-1;i>=0;i--){
if((val>>i)&1){
if(!a[i]){
a[i]=val;break;
}
val^=a[i];
}
}
}
bool find(int val){
for(int i=Len-1;i>=0;i--){
if((val>>i)&1){
if(a[i]){
val^=a[i];
}
else
return 0;
}
}
return 1;
}
};
LB merge(LB a,LB b){
LB ans=a;
for(int i=Len-1;i>=0;i--){
if(b[i]==0)continue;
ans.insert(b[i]);
}
return ans;
}
LB intersect(LB a,LB b){
LB ans= {},c=b,d=b;
for(int i=0;i<Len;i++) {
int x=a[i];
if(!x)
continue;
int j=i;
int T=0;
for(; j>=0; --j){
if((x>>j)&1)
if(c[j]) {
x^=c[j];
T^=d[j];
} else
break;
}
if(!x)
ans[i]=T;
else {
c[j]=x;
d[j]=T;
}
}
return ans;
}
LB arr[maxn];
LB tr[maxn<<2];
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
void build(int rt,int l,int r){
if(l==r){
tr[rt]=arr[l];
return ;
}
build(ls,l,mid);
build(rs,mid+1,r);
tr[rt]=intersect(tr[ls],tr[rs]);
}
bool query(int rt,int l,int r,int L,int R,int val){
if(l>=L&&r<=R){
return tr[rt].find(val);
}
if(L<=mid)
if(!query(ls,l,mid,L,R,val))return 0;
if(R>mid)
if(!query(rs,mid+1,r,L,R,val))return 0;
return 1;
}
int main(){
int n,q;scanf("%d%d",&n,&q);
rep(i,1,n){
int k;scanf("%d",&k);
while(k--){
int val;scanf("%d",&val);
arr[i].insert(val);
}
}
build(1,1,n);
while(q--){
int l,r,val;scanf("%d%d%d",&l,&r,&val);
printf("%s\n",query(1,1,n,l,r,val)?"YES":"NO");
}
}