从左到右一共n个数,数字下标从1到n编号。
一共m次询问,每次询问是否能从第L个到第R个数中(包括第L个和第R个数)选出一些数使得他们异或为K。
数据量比较大。
输入请用快速读入
输出请用puts
Input
单组测试数据。 第一行一个整数n(0<n<=500,000)。 第二行n个整数,0<每个数<2^30。 第三行一个数m,表示询问次数(0<m<=500,000)。 接下来m行每行三个数,L,R,K(0<L<=R<=n,0<K<2^30)。
Output
M行,每行为YES或NO
Input示例
5 1 1 2 4 6 3 1 2 1 2 4 8 3 5 7
Output示例
YES NO NO
异或的问题当然是线性基了。
但是如何维护区间内的线性基呢?
线段树不太现实, 因为线性基只能暴力合并,再加上线段树就是三个log肯定炸了。
我们考虑一个以l为左端点的线性基, 并且每一个基存一下它出现的位置。
从后往前跑, 已经构造了i以后的线性基, 正在插入i。
如果线性基中他的位置存在一个数,就比较一下这个数的位置和i的大小关系,位置靠前的插入线性基, 位置考后的接着在线性基里跑。
复杂度O(NlongN)。
#include <iostream> #include <cstdio> using namespace std; #define reg register inline int read() { int res=0;char ch=getchar();bool flag=0; while(!isdigit(ch)) {if(ch=='-')flag=1;ch=getchar();} while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=getchar(); return flag ? -res : res; } int n, a[500005]; struct Lbase { int x, id; }f[500005][31]; int main() { n = read(); for (reg int i = 1 ; i <= n ; i ++) a[i] = read(); for (reg int i = n ; i >= 1 ; i --) { memcpy(f[i], f[i+1], sizeof f[i]); Lbase now = (Lbase){a[i], i}; for (reg int j = 30 ; j >= 0 ; j --) { if (now.x >> j) { if (!f[i][j].x) swap(now, f[i][j]); else { if (f[i][j].id > now.id) swap(now, f[i][j]); now.x ^= f[i][j].x; } } } } int T = read(); while(T--) { int l = read(), r = read(); int k = read(); for (reg int i = 30 ; i >= 0 ; i --) { if ((k >> i) & 1) { if (f[l][i].id <= r and f[l][i].x) k ^= f[l][i].x; } } if (!k) puts("Yes"); else puts("No"); } return 0; }