题目大意
从左到右一共
n
个数,数字
一共
m
次询问,每次询问是否能从第
n≤5∗105
ai,K<230
m≤5∗105
解题思路
求一堆数能否异或成
k
,一个很显然的思路就是构出这堆数的线性基,然后看一下能不能用线性基里的数表示
那么我们可以以序列中的每个位置为开头,最后一个位置为结尾构造线性基,并且线性基中的每个位置额外存下这个数在序列中的位置。判断
k
的时候就把k在线性基中跑,当失配或者当前值对应序列中的位置大于
现在的问题是如何快速构造这
n
个线性基。考虑从后往前构造。假设当前已经构好了后i个数的线性基,要把第i个数插进去。首先让
具体实现看程序!
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 5e5 + 5;
struct Node {
int num, side;
Node (int a, int b) {num = a, side = b;}
Node () {}
};
Node f[MAXN][30];
int n, m, a[MAXN];
void read(int &x) {
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
x = 0;
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
int main() {
read(n);
for (int i = 1; i <= n; i ++) read(a[i]);
for (int i = n; i; i --) {
memcpy(f[i], f[i + 1], sizeof f[i]);
Node now = Node(a[i], i);
for (int j = 29; j + 1; j --) {
if (!(now.num & (1 << j))) continue;
if (!f[i][j].num) {swap(f[i][j], now); break;} else {
if (now.side < f[i][j].side) swap(f[i][j], now);
now.num ^= f[i][j].num;
}
}
}
read(m);
for (int i = 1; i <= m; i ++) {
int l, r, k;
read(l), read(r), read(k);
for (int j = 29; j + 1; j --) {
if (!(k & (1 << j))) continue;
if (f[l][j].num == 0 || f[l][j].side > r) break;
k ^= f[l][j].num;
}
if (!k) puts("YES"); else puts("NO");
}
}