线性基+线段树
线性基+线段树
t组数据,n个数的序列,q次查询,取l,r区间中的数,使得这些数异或后 或 (|)上k的最大值。
因为最后要 或 上 k,在二进制中,k为1的位置,最后结果也会是1,所以取数的时候,要a[i] & (~k),把一些位置的1消掉。再求最大异或。
举个例子:k = 8,a[] = {6(110), 10(1010)},如果直接求最大异或 | k,答案是12;如果进行a[i]&(~k)消掉一些1,答案是14;
用线段树维护。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
struct tree
{
LL l, r;
LL d[70];
}t[40010];
LL a[10010], k;
void built(LL l, LL r, LL x) {
t[x].l = l, t[x].r = r;
if(l == r) {
memset(t[x].d, 0, sizeof(t[x].d));
LL b = a[l] & (~k);
for(LL i = 60; i >= 0; i--) {
if(b & (1LL << i)) {
if(t[x].d[i]) b ^= t[x].d[i];
else {
t[x].d[i] = b;
break;
}
}
}
return ;
}
LL mid = (l + r) / 2;
built(l, mid, x*2);
built(mid + 1, r, x*2+1);
for(LL j = 60; j >= 0; j--) {
if(t[x*2].d[j]) {
LL b = t[x*2].d[j];
for(LL i = 60; i >= 0; i--) {
if(b & (1LL << i)) {
if(t[x].d[i]) b ^= t[x].d[i];
else {
t[x].d[i] = b;
break;
}
}
}
}
if(t[x*2+1].d[j]) {
LL b = t[x*2+1].d[j];
for(LL i = 60; i >= 0; i--) {
if(b & (1LL << i)) {
if(t[x].d[i]) b ^= t[x].d[i];
else {
t[x].d[i] = b;
break;
}
}
}
}
}
}
LL ans[70];
void ask(LL l, LL r, LL x) {
if(l <= t[x].l && t[x].r <= r) {
for(LL j = 60; j >= 0; j--) {
LL b = t[x].d[j];
if(b) {
for(LL i = 60; i >= 0; i--) {
if(b & (1LL << i)) {
if(ans[i]) b ^= ans[i];
else {
ans[i] = b;
break;
}
}
}
}
}
return ;
}
LL mid = (t[x].l + t[x].r) / 2;
if(l <= mid) ask(l, r, x*2);
if(r > mid) ask(l, r, x*2+1);
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
LL n, q;
scanf("%lld %lld %lld", &n, &q, &k);
for(LL i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
built(1, n, 1);
while(q--) {
LL l, r;
scanf("%lld %lld", &l, &r);
memset(ans, 0, sizeof(ans));
ask(l, r, 1);
LL sum = 0;
for(LL i = 60; i >= 0; i--) {
if((sum ^ ans[i]) > sum) sum ^= ans[i];
}
printf("%lld\n", sum | k);
}
}
return 0;
}
t组数据,n个数的序列,m次操作,操作1:0 l r,询问[l,r]最大异或。操作2:1 x 在序列最后面加入x
看这个大佬的博客吧https://www.cnblogs.com/KirinSB/p/11248546.html
#include <cstdio>
#include <cstring>
int d[35], nd[1000010][35], mpos[1000010][35], pos[35];
void add(int x, int r) {
int rr = r;
for(int i = 31; i >= 0; i--) {
if(x & (1 << i)) {
if(d[i]) {
if(pos[i] < r) {
int tmp = pos[i];
pos[i] = r;
r = tmp;
tmp = x;
x = d[i];
d[i] = tmp;
}
x ^= d[i];
}
else {
d[i] = x;
pos[i] = r;
break;
}
}
}
for(int i = 31; i >= 0; i--) {
nd[rr][i] = d[i];
mpos[rr][i] = pos[i];
}
}
int ask(int l, int r) {
int ret = 0;
for(int i = 31; i >= 0; i--) {
if(mpos[r][i] >= l) {
if((ret ^ nd[r][i]) > ret) ret ^= nd[r][i];
}
}
return ret;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
memset(d, 0, sizeof(d));
memset(pos, 0, sizeof(pos));
int n, m, a;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a);
add(a, i);
}
int last = 0;
while(m--) {
int op, l, r;
scanf("%d", &op);
if(op == 0) {
scanf("%d %d", &l, &r);
l = (l ^ last) % n + 1;
r = (r ^ last) % n + 1;
if(l > r) {
int tmp = l;
l = r;
r = tmp;
}
last = ask(l, r);
printf("%d\n", last);
}
else {
scanf("%d", &a);
a ^= last;
n++;
add(a, n);
}
}
}
return 0;
}