题目大意:给定a[1...n],Q次询问求A[L...R]的异或组合再或上K的最大值。
思路:学长的ppt上讲过怎么维护区间线性基。(不是线段树)详情看代码的插入操作。因为最后答案要或上K,因此K的二进制上为1的位最后一定为1,那么我们自然希望去掉这些位的影响,这样查询到的[L,R]的最大异或值再或上K就是最优解。那么我们把K按位取反后(设为T),将每一个数&上T再插入到线性基中即可。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
int b[maxn][35],pos[maxn][35],base[35];
inline bool insert(int h,int x)//维护区间[1,h]内的线性基
{
for(int i=0;i<=30;i++)
b[h][i]=b[h-1][i],pos[h][i]=pos[h-1][i];
int tmp=h;
for(int i=30;i>=0;i--)
{
if(x&base[i])
{
if(b[h][i])
{
if(pos[h][i]<tmp)
{
swap(pos[h][i],tmp);
swap(b[h][i],x);
}
x^=b[h][i];
}
else
{
b[h][i]=x;
pos[h][i]=tmp;
return 1;
}
}
}
return 0;
}
int get_max(int l,int r)//求区间[l,r]内的最大异或值
{
int ans=0;
for(int i=30;i>=0;i--) //得到区间[l,r]内的线性基
if(pos[r][i]>=l&&(ans^b[r][i])>ans)
ans^=b[r][i];
return ans;
}
int main()
{
for(int i=0;i<=30;i++)
base[i]=1<<i;
int t,n,q,k,l,r,tmp;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&q,&k);
tmp=0;
for(int i=30;i>=0;i--)
{
if(k&base[i])
;
else
tmp+=base[i];
}
for(int i=1;i<=n;i++)
{
scanf("%d",&l);
insert(i,l&tmp);
}
for(int i=0;i<q;i++)
{
scanf("%d%d",&l,&r);
printf("%d\n",get_max(l,r)|k);
}
}
return 0;
}