2019杭电多校第一场hdu6579 Operation(线性基)
Operation
解题思路
把右边的数尽量往高位放,构造线性基的时候同时记录其在原序列中的位置,在可以插入的时候如果那个位置上存在的数字的位置比新放入的要小,就把旧的往后挤。用这种发现构造前缀线性基,求最大前缀和的时候只有忽略位置比l小的即可。
代码如下
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read(){
int res = 0, w = 0; char ch = 0;
while(!isdigit(ch)){
w |= ch == '-', ch = getchar();
}
while(isdigit(ch)){
res = (res << 3) + (res << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -res : res;
}
const int N = 1000005;
int a[N];
int b[N][40], pos[N][40];
void insert(int k, int x)
{
for(int i = 30; i >= 0; i --){
b[k][i] = b[k - 1][i];
pos[k][i] = pos[k - 1][i];
}
int t = k;
for(int i = 30; i >= 0; i --){
if((x >> i) & 1){
if(b[t][i]){
if(pos[t][i] < k){
swap(b[t][i], x);
swap(pos[t][i], k);
}
x ^= b[t][i];
}
else {
b[t][i] = x;
pos[t][i] = k;
break;
}
}
}
}
int query(int l, int r)
{
int ans = 0;
for(int i = 30; i >= 0; i --){
if(pos[r][i] >= l){
if((ans ^ b[r][i]) > ans)
ans ^= b[r][i];
}
}
return ans;
}
int main()
{
int T;
cin >> T;
while(T --){
int n, m;
n = read(), m = read();
for(int i = 1; i <= n; i ++){
a[i] = read();
insert(i, a[i]);
}
int last = 0;
for(int i = 1; i <= m; i ++){
int opt;
opt = read();
if(opt == 0){
int l, r;
l = read(), r = read();
l = (l ^ last) % n + 1;
r = (r ^ last) % n + 1;
if(l > r)
swap(l, r);
last = query(l, r);
printf("%d\n", last);
}
else {
int x = read();
++n;
insert(n, x ^ last);
}
}
}
return 0;
}