给出
n
≤
1
e
4
n\leq1e4
n≤1e4个数,他们的值域
w
≤
1
e
8
w\leq1e8
w≤1e8。以及有
q
≤
1
e
5
q\le1e5
q≤1e5次查询,每次查询询问区间中的子集异或和或上
k
k
k的最大值。
k
k
k的二进制为
1
1
1的位置答案必定是
1
1
1,只要考虑非
1
1
1的位置异或和最大,可以让所有的元素在
1
1
1处都为0。
问题转化为了求区间最大异或和的问题,这个用线段树维护线性基的合并,线段树每个结点都开一个
l
o
g
w
logw
logw大小的线性基,合并的时候暴力插入。时间复杂度是
O
(
n
l
o
g
n
l
o
g
w
)
O(nlognlogw)
O(nlognlogw)的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e4+7;
const int M=30;
int a[N];
int ans[30];
int b[N<<2][30];
void add(int b[],int x) {
for(int i=27;i>=0;i--) {
if(x&(1LL<<i)) {
if(!b[i]) {
b[i]=x;
break;
}
else x^=b[i];
}
}
}
void pushup(int rt) {
for(int i=27;i>=0;i--)
b[rt][i]=b[rt<<1][i];
for(int i=27;i>=0;i--)
add(b[rt],b[rt<<1|1][i]);
}
void build(int rt,int l,int r) {
if(l==r) {
add(b[rt],a[l]);
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void query(int rt,int l,int r,int L,int R) {
if(R<l||L>r) return;
if(L<=l&&r<=R) {
for(int i=27;i>=0;i--)
add(ans,b[rt][i]);
return;
}
int mid=(l+r)>>1;
query(rt<<1,l,mid,L,R);
query(rt<<1|1,mid+1,r,L,R);
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
int n,q,k;
scanf("%d%d%d",&n,&q,&k);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
a[i]=a[i]&(~k);
}
build(1,1,n);
while(q--) {
int l,r;
scanf("%d%d",&l,&r);
for(int i=27;i>=0;i--) ans[i]=0;
query(1,1,n,l,r);
int res=0;
for(int i=27;i>=0;i--) {
if((res^ans[i])>res) {
res^=ans[i];
}
}
printf("%d\n",res|k);
}
}
return 0;
}