Xor Query [ABC223H]

https://atcoder.jp/contests/abc223/tasks/abc223_h

题解

奇技淫巧。。。

首先当然是想到了线性基 但是区间的限制怎么办呢?

考虑固定右端点,对于线性基的每一位记录一个 \(id\) 表示这一位的值是从 \(a_{id}\) 来的

每次加入一个 \(a_i\) 时,从大到小枚举第 \(j\) 位,如果 \(a_i\) 的第 \(j\) 位为 \(1\)

如果线性基的第 \(j\) 位没有值就把它设为 \(a_i\) 并且跳出循环

否则如果 \(id_j < i\) 就交换 \(id_j,i\),交换线性基第 \(j\) 位的值和 \(a_i\) ,然后继续枚举低位

查询时只需要保证所有需要修改的位 \(j\) 都满足 \(l \le id_j\) 即可

实现和普通的异或线性基差别不大 见代码

由于此篇题解比较垃圾所以没有证明,只是记录一下这个技巧(狗头)

#include <bits/stdc++.h>
#define N 400005
using namespace std;
typedef long long ll;

template <typename T>
inline void read(T &num) {
	T x = 0, f = 1; char ch = getchar();
	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x<<1) + (x<<3) + (ch^'0');
	num = x * f;
}

int n, m;
ll a[N][60]; int id[N][60];

inline void upd(ll x, int p) {
	int P = p;
	for (int i = 60; ~i; i--) a[P][i] = a[P-1][i], id[P][i] = id[P-1][i];
	for (int i = 60; ~i; i--) if ((x>>i)&1) {
		if (!a[P][i]) {
			a[P][i] = x; id[P][i] = p; break;
		} else if (p > id[P][i]) {
			swap(a[P][i], x); swap(id[P][i], p);
		}
		x ^= a[P][i];
	}
}

int main() {
	read(n); read(m);
	for (int i = 1; i <= n; i++) {
		ll x; read(x); upd(x, i);
	}
	while (m--) {
		int l, r, ok = 1; ll x; read(l); read(r); read(x);
		for (int i = 60; ~i; i--) if ((x>>i)&1) {
			if (!a[r][i] || id[r][i] < l) { ok = 0; break; }
			else x ^= a[r][i];
		}
		puts(ok?"Yes":"No");
	}
	return 0;
}
posted @ 2021-10-22 11:08  AK_DREAM  阅读(235)  评论(0编辑  收藏  举报