补题地址:https://nanti.jisuanke.com/t/A1607
题目:
Consider an array A with n elements . Each of its element is A[i](1≤i≤n). Then gives two integers Q, K, and Q queries follow . Each query , give you L, R, you can get Z by the following rules.
To get Z , at first you need to choose some elements from A[L] to A[R] ,we call them A[i1],A[i2]…A[it] , Then you can get number Z=K or (A[i1] xor A[i2] … xor A[it]) .
Please calculate the maximum ZZ for each query .
Input
Several test cases .
First line an integer T (1≤T≤10) . Indicates the number of test cases.Then T test cases follows . Each test case begins with three integer N, Q,K (1≤N≤10000, 1≤Q≤100000, 0≤K≤100000). The next line has N integers indicate A[1] to A[N] (0≤A[i]≤108). Then Q lines , each line two integer L,R (1≤L≤R≤N).
Output
For each query , print the answer in a single line.
样例输入
1 5 3 0 1 2 3 4 5 1 3 2 4 3 5
样例输出
3 7 7
解题思路:
求区间异或值or已知数k的最大值,区间问题,多次查询,要用到线段树,线段树的叶子节点是单个的线性基,非叶子都是合并后的线性基。
线性基的合并可以参考这道例题。
本题很关键的一个点:因为要求或之后的结果最大,k已知,那么k中为1的位或之后还是1,所以k中为0的那些位需要用区间异或值来弥补,这就是说,k中为0的那些位,在区间异或值中尽量为1,且求最大异或值时只考虑区间的数m 在k中为0的那些位。此时,我们不关心区间异或值是否取最大,或者取多少,只要最终的整个结果最大即可。
对k各位取反,在让区间中的值都和取反后的k做与运算,这样以后,原k中为1的那些位 在区间中的数上 都是0 (因为k中为1的位取反后是0,0和任何数与都是0),而区间的数中为1的位说明 原k中那些位为0,原数中那些位为1。所以最终答案就变成了求新区间的数的最大异或值(让原k中为0的那些位所表示的数最大),再与原k做或运算(原k中为1的那些位在最大异或值中都是0),举个例子试试吧。
ac代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=10005;
const int max_base=30;
typedef long long ll;
int a[maxn],xian[4*maxn][max_base+3],ans[max_base+3];
int n,q,k,t,L,R;
void update(int id)
{
int x=id<<1,y=id<<1|1;
memcpy(xian[id],xian[x],sizeof(xian[x]));//id的线性基初始化左子树的线性基
for(int k=max_base;k>=0;k--)
{
int tmp=xian[y][k];
for(int j=max_base;j>=0 && tmp;j--)
{
if(tmp>>j&1)
{
if(xian[id][j])
tmp^=xian[id][j];
else
{
xian[id][j]=tmp;
break;
}
}
}
}
}
void build(int l,int r,int id)
{
if(l==r)
{
for(int i=max_base;i>=0;i--)
if(a[l]>>i&1)
{
if(xian[id][i])
a[l]^=xian[id][i];
else
{
xian[id][i]=a[l];
break;
}
}
return ;
}
int mid=(l+r)>>1;
build(l,mid,id<<1);
build(mid+1,r,id<<1|1);
update(id);
}
void query(int l,int r,int x,int y,int id)//要查的区间为(x,y)
{
if(x<=l && r<=y)//如果区间不能直接查到的话,线性基合并,合并的结果存入ans【】中
{
for(int k=max_base;k>=0;k--)
{
int tmp=xian[id][k];
for(int j=max_base;j>=0 && tmp;j--)
{
if(tmp>>j&1)
{
if(ans[j])
tmp^=ans[j];
else
{
ans[j]=tmp;
break;
}
}
}
}
return ;//记得写!
}
int mid=(l+r)>>1;
if(x<=mid) query(l,mid,x,y,id<<1);
if(y>=mid+1) query(mid+1,r,x,y,id<<1|1);
}
int main() {
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
memset(xian,0,sizeof(xian));
scanf("%d %d %d",&n,&q,&k);
k=~k;
for(int i=1;i<=n;i++)
{
scanf("%d", &a[i]);
a[i]&=k;
}
k=~k;
build(1,n,1);
while(q--)
{
scanf("%d %d",&L,&R);
memset(ans,0,sizeof(ans));
query(1,n,L,R,1);
int res=0;
for(int i=max_base;i>=0;i--)
res=max(res,res^ans[i]);
printf("%d\n",res|k);
}
}
return 0;
}