2019牛客多校第四场B xor(线性基求交)题解
题意:
给\(n\)个集合,每个集合有一些数。给出\(m\)个询问,再给出\(l\)和\(r\)和一个数\(v\),问你任意的\(i \in[l,r]\)的集合,能不能找出子集异或为\(v\)。简单点说,\(v\)能用\([l,r]\)任意一个集合的子集异或和表示。
思路:
子集异或和显然是用线性基。我们用线段树维护任意区间的线性基交集即可。
代码:
/**
求交集 O(logn * logn)
**/
LBasis intersection(const LBasis &a, const LBasis &b){
LBasis ans, c = b, d = b;
ans.init();
for (int i = 0; i <= 32; i++){
ll x = a.d[i];
if(!x)continue;
int j = i;
ll T = 0;
for(; j >= 0; --j){
if((x >> j) & 1)
if(c.d[j]) {x ^= c.d[j]; T ^= d.d[j];}
else break;
}
if(!x) ans.d[i] = T;
else {c.d[j] = x; d.d[j] = T;}
}
return ans;
}
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 50000 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
using namespace std;
struct LBasis{
ll d[33];
int tot;
void init(){
memset(d, 0, sizeof(d));
tot = 0;
}
bool insert(ll x){
for(int i = 32; i >= 0; i--){
if(x & (1LL << i)){
if(d[i]) x ^= d[i];
else{
d[i] = x;
return true;
}
}
}
return false;
}
bool checkin(ll x){
for(int i = 32; i >= 0; i--){
if(x & (1LL << i)){
if(d[i]) x ^= d[i];
else return false;
}
}
return true;
}
};
LBasis intersection(const LBasis &a, const LBasis &b){
LBasis ans, c = b, d = b;
ans.init();
for (int i = 0; i <= 32; i++){
ll x = a.d[i];
if(!x)continue;
int j = i;
ll T = 0;
for(; j >= 0; --j){
if((x >> j) & 1)
if(c.d[j]) {x ^= c.d[j]; T ^= d.d[j];}
else break;
}
if(!x) ans.d[i] = T;
else {c.d[j] = x; d.d[j] = T;}
}
return ans;
}
LBasis node[maxn << 2];
void pushup(int rt){
node[rt] = intersection(node[rt << 1], node[rt << 1 | 1]);
}
void build(int l, int r, int rt){
if(l == r){
int sz;
scanf("%d", &sz);
node[rt].init();
while(sz--){
ll x;
scanf("%lld", &x);
node[rt].insert(x);
}
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
bool query(int L, int R, int l, int r, ll v, int rt){
if(L <= l && R >= r){
return node[rt].checkin(v);
}
int m = (l + r) >> 1;
bool ok = true;
if(L <= m)
ok = ok && query(L, R, l, m, v, rt << 1);
if(R > m)
ok = ok && query(L, R, m + 1, r, v, rt << 1 | 1);
return ok;
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
build(1, n, 1);
while(m--){
int l, r;
ll x;
scanf("%d%d%lld", &l, &r, &x);
if(query(l, r, 1, n, x, 1)) printf("YES\n");
else printf("NO\n");
}
return 0;
}