题目链接
给定一个数组,从任给区间中选几个数,使得这几个数得异或和最大,求这个最大值。
这个题一开始想的是线段树维护区间线性基,但是写起来太长太费劲,而且合并的时候要遍历一遍线性基,复杂度太高了,估计过不了。
求解仍然采用线性基,但是计算第i个数是哪个区间的线性基成员,记录距离位置r最近的线性基成员的位置,查询最大值的时候遍历线性基即可。
假设我们已知
{
a
1
,
a
2
,
⋅
⋅
⋅
,
a
r
}
\{a_1,a_2,\cdot \cdot \cdot ,a_r \}
{a1,a2,⋅⋅⋅,ar}的线性基分布pos[r][]以及线性基LB[r][]。那么对于
{
a
1
,
a
2
,
⋅
⋅
⋅
,
a
r
,
a
r
+
1
}
\{a_1,a_2,\cdot \cdot \cdot ,a_r , a_{r+1}\}
{a1,a2,⋅⋅⋅,ar,ar+1}的线性基,我们就需要用ar+1去代替LB[r][]中的元素,得到这个序列的线性基 和线性基的分布。
根据线性基的构成,当 x&(1<<i) && !d[i] 时,我们可以用x代替d[i],也是将插入元素变成d[i],x变为线性基元素。注意现在插入操作需要位置和元素值两个变量来描述,所以在x与d[i]的交换过程中,它们两个的位置不要忘记交换。
在构造完线性基之后,对于每一个查询区间[l,r],我们只需要查询在序列
{
a
1
,
a
2
,
⋅
⋅
⋅
,
a
r
}
\{a_1,a_2,\cdot \cdot \cdot ,a_r \}
{a1,a2,⋅⋅⋅,ar}中,哪些线性基的位置大于等于l即可,然后贪心的加入。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
template<class T> void _deb(const char *name,T val){
cout<<name<<val<<endl;
}
const int maxn=5e5+5;
int N,Q;
int LB[maxn][22],pos[maxn][22];
void copy(int k);
void prework(int k,int n);
int main(){
scanf("%d",&N);
rep(i,1,N+1){
int temp;
scanf("%d",&temp);
copy(i);
prework(i,temp);
}
scanf("%d",&Q);
rep(i,0,Q){
int l,r;
scanf("%d%d",&l,&r);
int ans=0;
for(register int i=20;i>=0;i--){
if(l<=pos[r][i])
ans=max(ans,ans^LB[r][i]);
}
printf("%d\n",ans);
}
re 0;
}
void copy(int k){
rep(i,0,21){
LB[k][i]=LB[k-1][i];
pos[k][i]=pos[k-1][i];
}
}
void prework(int k,int n){
int r=k;
for(register int i=20;i>=0;i--){
if(n&(1<<i)){
if(!LB[r][i]){
LB[r][i]=n;
pos[r][i]=k;
return;
}
if(pos[r][i]<k){
swap(LB[r][i],n);
swap(pos[r][i],k);
}
n^=LB[r][i];
}
}
}