题目
解法
壹
暴力用线段树维护,线性基合并是 \(\mathcal O(n\log n\log^2 c)\) 的。
考虑线性基计算最大值时从最高位向低位异或,如果第 \(i\) 位因此变成 \(1\) 就异或。
首先按 \(r\) 排序,将 \(1\) 到当前 \(r\) 的 \(a_i\) 加入线性基。令 \(lim[i]\) 为第 \(i\) 位为 \(1\) 的最大位置(注意这不一定是最初态)。
先看看 Insert()
。
void Insert(int x,int pos) {
fep(i,20,0)
if((x>>i)&1) {
if(!d[i]) {d[i]=x,lim[i]=pos; break;}
if(pos>lim[i]) swap(pos,lim[i]),swap(x,d[i]);
x^=d[i];
}
}
我们将位置大的优先选择。而且不会出现 \(a_x\) 被位置小于自己的数 \(a_y\) 异或导致 \(a_x\ \text{xor}\ a_y\) 存在必须保证取到位置 \(y\) 而不是传进去的参数 \(x\)。
那么最后的线性基异或和最大值异或的条件就多了一个:传进去的 \(l\)(左边界)小于等于 \(lim[i]\)。
这道题还可以离线做,只要将 \(r\) 全插进去就行了,时间复杂度 \(\mathcal O(n\log n)\)。
贰
可以离线与分治。
二分数组下标,求出 \(mid\) 开始的后缀线性基与前缀线性基。对于跨过 \(mid\) 的询问,将其对应的前缀与后缀合并起来求得答案,其它的询问递归处理。
每个询问只会合并一次,故时间复杂度 \(\mathcal O(q\log^2 c)\)。
对于分治部分,有一个 \(\text{OI Wiki}\) 的主定理:
此题 \(a=b=2,k=1\),故时间复杂度 \(\mathcal O(n\log^2 n)\)。
总时间复杂度 \(\mathcal O(n\log^2 n+q\log^2 c)\)。
代码
#include <cstdio>
#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=5e5+5;
int n,a[maxn],q,ans[maxn],d[50],lim[50];
struct node {
int l,r,id;
bool operator < (const node t) {
return r<t.r;
}
} s[maxn];
void Insert(int x,int pos) {
fep(i,20,0)
if((x>>i)&1) {
if(!d[i]) {d[i]=x,lim[i]=pos; break;}
if(pos>lim[i]) swap(pos,lim[i]),swap(x,d[i]);
x^=d[i];
}
}
int calc(int l) {
int ret=0;
fep(i,20,0)
if(l<=lim[i] && ret<(d[i]^ret)) ret^=d[i];
return ret;
}
int main() {
n=read(9);
rep(i,1,n) a[i]=read(9);
q=read(9);
rep(i,1,q) s[i].id=i,s[i].l=read(9),s[i].r=read(9);
sort(s+1,s+q+1);
int Pointer=0;
rep(i,1,q) {
while(Pointer<s[i].r) {
++Pointer;
Insert(a[Pointer],Pointer);
}
ans[s[i].id]=calc(s[i].l);
}
rep(i,1,q) print(ans[i],'\n');
return 0;
}