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;
}