2019牛客暑期多校训练营四 B-xor(线性基求交)

题意:

给出 \(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;
}
posted @ 2019-10-28 00:43  Chase。  阅读(173)  评论(0编辑  收藏  举报