題意:你有兩種操作,0是查詢[l, r] 區間的異或最大值,1是加入一個值並另n+1,m次操作。
思路:這道題強制在線,記錄一下前綴基,在插入的時候維護一個靠右儘可能在高位的區間,每次更新右邊的值。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50 + 10;
int p[500010][maxn], pos[500010][maxn]; //pos用來記錄位置
int num;
void add(int x, int num)
{
int now = num;
for(int i = 31; i >= 0; --i)
{
if(x & (1 << i))
{
if(!p[num][i]) //如果沒更新過
{
p[num][i] = x;
pos[num][i] = now;
break;
}
else
{
if(now > pos[num][i]) //如果更靠右就交換
{
swap(now, pos[num][i]);
swap(x, p[num][i]);
}
}
x ^= p[num][i];
}
}
}
int query(int l, int r)
{
int res = 0;
for(int i = 31; i >= 0; --i)
{
if(pos[r][i] >= l) //只考慮其右邊的貢獻
res = max(res, res ^ p[r][i]);
}
return res;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, m;
scanf("%d%d", &n, &m);
memset(p, 0, sizeof(p));
memset(pos, 0, sizeof(pos));
for(int i = 1; i <= n; ++i)
{
for(int j = 31; j >= 0; --j)
{
p[i][j] = p[i - 1][j];
pos[i][j] = pos[i - 1][j];
}
int x;
scanf("%d", &x);
add(x, i);
}
int lastans = 0;
while(m--)
{
int op;
scanf("%d", &op);
if(op == 0)
{
int l, r;
scanf("%d%d", &l, &r);
l = (l ^ lastans) % n + 1, r = (r ^ lastans) % n + 1;
if(l > r)
swap(l, r);
lastans = query(l, r);
printf("%d\n", lastans);
}
else if(op == 1)
{
++n;
for(int j = 31; j >= 0; --j)
{
p[n][j] = p[n - 1][j];
pos[n][j] = pos[n - 1][j];
}
int x;
scanf("%d", &x);
add(x ^ lastans, n);
}
}
}
return 0;
}
/*
1
3 3
0 1 2
0 1 1
1 3
0 3 4
*/