题意:
给出 (n) 个序列从 (1) 到 (n),以及 (m) 个询问,每次询问所有 ([l,r]) 区间的序列是否能异或出 (x)。
分析:
对于 ([l,r]) 区间序列来说,要判断是不是都能异或出 (x),可以求出 ([l,r]) 区间的序列的线性基的交集,然后在这个交集判断即可,那么:
对 (n) 个序列的线性基建线段树,pushup 时对左右叶子做一次线性基求交。
询问用线段树判断区间交的线性基能否插入 (x),如果能插入则说明这段区间无法异或出 (x),反之可以。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 50000 + 5;
struct Base {
static const int maxN = 31;//int-31 or long long-62
int tot, flag;
int d[maxN + 5];
int nd[maxN + 5];//used for kth
Base() {
tot = flag = 0;
memset(d, 0, sizeof d);
memset(nd, 0, sizeof nd);
}
bool ins(LL x) {
for (int i = maxN; ~i; i--) {
if (x & (1LL << i)) {
if (d[i]) {
x ^= d[i];
} else {
d[i] = x;
return true;
}
}
}
flag = 1;
return false;
}
bool canIns(LL x) {
for (int i = maxN; ~i; i--) {
if (x & (1LL << i)) {
if (d[i]) {
x ^= d[i];
} else {
return true;
}
}
}
return false;
}
LL queryMax() {
LL ans = 0;
for (int i = maxN; ~i; i--) ans = max(ans, ans ^ d[i]);
return ans;
}
LL queryMin() {
for (int i = 0; i <= maxN; i++) if (d[i]) return d[i];
return -1LL;
}
void rebuild() {
for (int i = maxN; ~i; i--) {
for (int j = i - 1; ~j; j--) {
if (d[i] & (1LL << j)) d[i] ^= d[j];
}
}
for (int i = 0; i <= maxN; i++) if (d[i])
nd[tot++] = d[i];
}
LL kth(LL k) {
if (flag) k--;
if (!k) return 0LL;
if (k >= (1LL << tot)) return -1LL;
LL ans = 0;
for (int i = maxN; ~i; i--) {
if (k & (1LL << i)) ans ^= nd[i];
}
return ans;
}
void merge(Base b) {//与b取并集
for (int i = maxN; ~i; i--) if (b.d[i])
ins(b.d[i]);
}
Base mixed(Base B) {//与b取交集
Base All, C, D;
// All.init(), C.init(), D.init();
for (int i = maxN; ~i; i--) {
All.d[i] = d[i];
D.d[i] = 1LL << i;
}
for (int i = maxN; ~i; i--) {
if (B.d[i]) {
LL v = B.d[i], k = 0;
bool can = true;
for (int j = maxN; ~j; j--) {
if (v & (1LL << j)) {
if (All.d[j]) {
v ^= All.d[j];
k ^= D.d[j];
} else {
can = false;
All.d[j] = v;
D.d[j] = k;
break;
}
}
}
if (can) {
LL v = 0;
for (int j = maxN; ~j; j--) {
if (k & (1LL << j)) {
v ^= d[j];
}
}
C.ins(v);
}
}
}
return C;
}
} lb[N << 2];
int n, m, sz, l, r, x;
void build(int rt, int l, int r) {
if (l == r) {
scanf("%d", &sz);
for (int i = 1; i <= sz; i++) {
scanf("%d", &x);
lb[rt].ins(x);
}
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
lb[rt] = lb[rt << 1].mixed(lb[rt << 1 | 1]);
}
bool query(int rt, int l, int r, int ql, int qr, int w) {
if (l >= ql && r <= qr) {
return !lb[rt].canIns(w);
}
int mid = l + r >> 1;
if (ql <= mid && !query(rt << 1, l, mid, ql, qr, w)) return false;
if (qr > mid && !query(rt << 1 | 1, mid + 1, r, ql, qr, w)) return false;
return true;
}
int main() {
scanf("%d %d", &n, &m);
build(1, 1, n);
while (m--) {
scanf("%d %d %d", &l, &r, &x);
if (x == 0) {
puts("YES");
continue;
}
if (query(1, 1, n, l, r, x)) puts("YES");
else puts("NO");
}
return 0;
}