#线性基#CF1100F Ivan and Burgers
分析
线段树上直接维护线性基是三个log的。(一定要合并)
考虑一种分治做法,在 \([l,mid]\) 和 \((mid,r]\) 的询问分治处理,
跨过 \([mid,mid+1]\) 的维护 \([i,mid]\) 的线性基和 \([mid+1,j]\) 的线性基,
询问时合并起来,复杂度就是 \(O((n+Q)\log n\log \max\{a_i\})\)
还有一种做法就是以右端点为基准,然后尽量让线性基中的数字位置靠近右端点,插入时能替换就替换。
可以在线询问,线性基的数位置在左端点或之后就可以参与询问,这样时间复杂度是 \(O((n+Q)\log \max\{a_i\})\)
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=500011; int n;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
struct Vector_Space{
int re[20],tim[20];
void BUILD(){
memset(re,0,sizeof(re));
memset(tim,0,sizeof(tim));
}
void Insert(int x,int j){
for (int i=19;~i;--i)
if ((x>>i)&1){
if (!re[i]) {re[i]=x,tim[i]=j; return;}
else{
if (tim[i]<j) swap(tim[i],j),swap(re[i],x);
x^=re[i];
}
}
}
int query(int l){
int x=0;
for (int i=19;~i;--i)
if (tim[i]>=l&&(x^re[i])>x) x^=re[i];
return x;
}
}H[N];
int main(){
n=iut();
for (int i=1;i<=n;++i){
int x=iut();
H[i]=H[i-1],H[i].Insert(x,i);
}
for (int Q=iut();Q;--Q){
int l=iut(),r=iut();
print(H[r].query(l)),putchar(10);
}
return 0;
}