题目链接:点我啊╭(╯^╰)╮
题目大意:
长度为
n
n
n 的序列,有
m
m
m 次操作
0
0
0
r
r
r
x
x
x :查询区间
[
l
,
r
]
[l, r]
[l,r] 的异或最大值
1
1
1
x
x
x :在序列末尾加入数
x
x
x
解题思路:
对每个
r
r
r 都构造一个线性基
那么对于一个
r
r
r 的线性基在插入过程中时,出现的位置靠右的数尽量放在高位
也就是要同时记录线性基里每个数出现的位置
如果发现可以插入,就将被替换的数字继续往低位推
求最大值的过程,从高位到低位遍历
如果该位的数字位于左端点的右侧,就可以参与计算
核心:前缀线性基 维护区间最大值
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int T, n, m, cnt;
int d[maxn][40], pos[maxn][40];
void add(int x, int t){
int ti = t;
for(int i=30; ~i; i--)
if(x >> i & 1){
if(!d[ti][i]){
d[ti][i] = x;
pos[ti][i] = t;
break;
}
if(t > pos[ti][i]){
swap(d[ti][i], x);
swap(pos[ti][i], t);
}
x ^= d[ti][i];
}
}
int qmax(int l, int r){
int ret = 0;
for(int i=30; ~i; i--)
if(pos[r][i] >= l)
ret = max(ret, ret ^ d[r][i]);
return ret;
}
int main() {
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
for(int i=1, x; i<=n; i++){
for(int j=0; j<=30; j++){
d[i][j] = d[i-1][j];
pos[i][j] = pos[i-1][j];
}
scanf("%d", &x);
add(x, i);
}
int cnt = n, ans = 0, op, l, r;
while(m--){
scanf("%d", &op);
if(op){
++cnt;
scanf("%d", &l);
for(int i=0; i<=30; i++){
d[cnt][i] = d[cnt-1][i];
pos[cnt][i] = pos[cnt-1][i];
}
add(l ^ ans, cnt);
} else {
scanf("%d%d", &l, &r);
l = (l^ans) % cnt + 1, r = (r^ans) % cnt + 1;
if(l > r) swap(l, r);
printf("%d\n", ans = qmax(l, r));
}
}
}
}