题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6579
题意:现在有 n n n个数, q q q次操作,每次操作可以在 n n n个数末尾添加一个数,或者询问 l l l到 r r r区间任选数字出来异或和最大。并且每次操作和上一次的答案相关。
解题心得:
- 一看区间询问异或和最大肯定时线性基没跑了。
- 这个题和 C F 1100 F CF1100F CF1100F题有点像,但是强制在线了,如果不强制在线,那么就是一个贪心处理的线性基,具体解法见 https://blog.csdn.net/yopilipala/article/details/96997808。
- 强制在线怎么办呢,那就求一个前缀线性基就行了,也就是说,因为线性基的空间占用很小就可以在每一个数字建立一个新的线性基,这个线性基和前面一个数字的线性基唯一的不同就是贪心插入了当前数字。这个时候就很简单了,和 C F 1100 F CF1100F CF1100F相同询问。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e6+100;
const ll maxm = 35;
ll n, m, num[maxn], lastens;
struct Cxx {
ll va, pos;
}cxx[maxn][maxm];//这里不但要记录值还需要记录一下位置,用于贪心
void init() {
scanf("%lld%lld", &n, &m);
lastens = 0;
for(ll i=1;i<=n;i++) scanf("%lld", &num[i]);
}
void insert(ll va, ll pos) {
for(ll i=0;i<maxm;i++) {
cxx[pos][i].va = cxx[pos-1][i].va;
cxx[pos][i].pos = cxx[pos-1][i].pos;
}
int Pos = pos;
for(ll i=31;i>=0;i--) {//这里贪心插入
if(va&(1<<i)) {
if(cxx[Pos][i].va == 0) {
cxx[Pos][i].va = va;
cxx[Pos][i].pos = pos;
break;
} else if(cxx[Pos][i].pos < pos) {
Cxx temp = cxx[Pos][i];
cxx[Pos][i].va = va;
cxx[Pos][i].pos = pos;
va = temp.va;
pos = temp.pos;
}
va ^= cxx[Pos][i].va;
}
}
}
ll query(ll l, ll r) {
ll sum = 0;
for(ll i=31;i>=0;i--) {
if(cxx[r][i].pos >= l) {
sum = max(sum ,sum^cxx[r][i].va);
}
}
return sum;
}
int main() {
// freopen("1.in.txt", "r", stdin);
ll t; scanf("%lld", &t);
while(t--) {
init();
for(ll i=1;i<=n;i++) insert(num[i], i); //将初始的n个数插进去
while(m--) {
ll ope; scanf("%lld", &ope);
if(ope == 0) {
ll l, r; scanf("%lld%lld",&l, &r);
l = (l^lastens)%n+1;
r = (r^lastens)%n+1;
if(l > r) swap(l, r);
lastens = query(l, r);
printf("%lld\n", lastens);
}else {
ll x; scanf("%lld", &x);
x = x ^ lastens;
num[++n] = x;
insert(num[n], n);
}
}
}
return 0;
}