给出n个数组,每个数组由多个数组成
有m个询问, l , r , x l,r,x l,r,x
询问第 l l l个到第 r r r个数组,能否都可以通过数组中的数异或得到
区间异或值很容易想到用线性基处理
bool check(LL x) {
for (int i = 31; i >= 0; i--) {
if (x & (LL(1) << i)) {
if (!d[i])return false; //无法由线性基异或得到
x ^= d[i];
}
}
return true;
}
我们可以将每个集合的异或,看成一个线性空间,用线性基表示
对于两个线性空间都包含x,相当于两个线性空间的交包含x
显然的是两个线性基的交仍然是线性空间,所以我们依旧用线性基表示
若 V 1 , V 2 V_{1},V_{2} V1,V2是线性空间, B 1 , B 2 B_{1},B_{2} B1,B2分别是他们的一组基,令 W = B 2 ∩ V 1 W=B_{2}\cap V_{1} W=B2∩V1,
若 B 1 ∪ ( B 2 − W ) B_{1} \cup (B_{2}-W) B1∪(B2−W)线性无关,则W是 V 1 − V 2 V_{1}-V_{2} V1−V2的一组基
解释下上面的话,
我们举个例子: B 1 = ( 0 , 2 , 4 , 8 ) B_{1}=(0,2,4,8) B1=(0,2,4,8), B 2 = ( 1 , 2 , 7 , 0 ) B_{2}=(1,2,7,0) B2=(1,2,7,0)
用c数组可以记录构造出的 b [ i ] b[i] b[i],所用到的b
最终 b [ i ] ∗ b[i]* b[i]∗(用到的b) ∗ * ∗(用到的a) = = 0 ==0 ==0,
那么 b [ a r g v ⋯   ] ⊕ b [ i ] = = a [ a r g v ⋯   ] b[argv\cdots] \oplus b[i]==a[argv\cdots] b[argv⋯]⊕b[i]==a[argv⋯]
friend Bit_Set operator +(const Bit_Set& a, const Bit_Set& b) {
Bit_Set a_b(a), c, res; //初始化a_b为a
for (int i = 31; i >= 0; i--) {
if (b.d[i]) { //将b[i]加入a_b
LL x = b.d[i], k = LL(1) << i;
bool flag = true;
for (int j = 31; j >= 0; j--) {
if (x & (LL(1) << j)) {
if (a_b.d[j]) {
x ^= a_b.d[j];
k ^= c.d[j]; //将用上的b元素计入k
} else {
flag = false; //若不能被a_b表示,将b[i]加入数组
a_b.d[j] = x;
c.d[j] = k; //将a_b中b元素标记
break;
}
}
}
if (flag) {
LL x = 0;
for (int j = 31; j >= 0; j--)
if (k & (LL(1) << j))
x ^= b.d[j];
//将用上的b元素和本身的b[i]异或在一起,
//由(a[argv---]^b[argv---]^b[i]==0),所得即为V1的贡献
res.insert(x);
}
}
}
return res;
}
void build(int root, int left, int right) {
if (left == right) { //构造线性基
int k; LL x;
scanf("%d", &k);
while (k--) {
scanf("%lld", &x);
tree[root].insert(x);
}
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = tree[root << 1] + tree[root << 1 | 1]; //合并构造线性基的交
}
bool query(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr)
return tree[root].check(x); //只要返回是否包含x即可
int mid = (left + right) >> 1; bool flag = true;
if (stdl <= mid) flag &= query(root << 1, left, mid, stdl, stdr);
if (stdr > mid)flag &= query(root << 1 | 1, mid + 1, right, stdl, stdr);
return flag;
}
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 50005;
class Bit_Set
{
public:
LL d[32];
Bit_Set() {
memset(d, 0, sizeof(d));
}
Bit_Set(const Bit_Set& t) {
for (int i = 0; i <= 31; i++)
d[i] = t.d[i];
}
void clear() {
memset(d, 0, sizeof(d));
}
void insert(LL x) {
for (int i = 31; i >= 0; i--) {
if (x & (LL(1) << i)) {
if (!d[i]) {
d[i] = x;
return;
}
x ^= d[i];
}
}
}
bool check(LL x) {
for (int i = 31; i >= 0; i--) {
if (x & (LL(1) << i)) {
if (!d[i])return false;
x ^= d[i];
}
}
return true;
}
void show() {
for (int i = 0; i <= 31; i++)
cout << i << ' ' << d[i] << '\n';
}
friend Bit_Set operator +(const Bit_Set& a, const Bit_Set& b) {
Bit_Set a_b(a), c, res;
for (int i = 31; i >= 0; i--) {
if (b.d[i]) {
LL x = b.d[i], k = LL(1) << i;
bool flag = true;
for (int j = 31; j >= 0; j--) {
if (x & (LL(1) << j)) {
if (a_b.d[j]) {
x ^= a_b.d[j];
k ^= c.d[j];
}
else {
flag = false;
a_b.d[j] = x;
c.d[j] = k;
break;
}
}
}
if (flag) {
LL x = 0;
for (int j = 31; j >= 0; j--)
if (k & (LL(1) << j))
x ^= b.d[j];
res.insert(x);
}
}
}
return res;
}
};
Bit_Set tree[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
int k; LL x;
scanf("%d", &k);
while (k--) {
scanf("%lld", &x);
tree[root].insert(x);
}
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
LL x;
bool query(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr)
return tree[root].check(x);
int mid = (left + right) >> 1; bool flag = true;
if (stdl <= mid) flag &= query(root << 1, left, mid, stdl, stdr);
if (stdr > mid)flag &= query(root << 1 | 1, mid + 1, right, stdl, stdr);
return flag;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
build(1, 1, n);
int l, r;
while (m--) {
scanf("%d%d%lld", &l, &r, &x);
if (query(1, 1, n, l, r))printf("YES\n");
else printf("NO\n");
}
}