JZOJ 5649. 【NOI2018模拟4.13】异或 (线性基高端操作)
https://gmoj.net/senior/#main/show/5649
和这题类似:
http://www.51nod.com/Challenge/Problem.html#problemId=1577
题解:
考虑线段树维护线性基,它TLE了。
考虑离线后从左往右建线性基,注意维护一个最大生成线性基,一个要加入的数若可以被线性基异或出来,找到组成它的数最小的那个,替换就好了。
这个怎么样都要\(O(log^2)\)
考虑改一下线性基的一些定义。
对于每一位的基,记\(b[i]\)表示最右的左端点,满足当前\([b[i],r]\)能搞出这一位的基,也要记一下基是什么。
修改时,如果空的就插进去,不然看谁更小,就保留谁,另一个下去更新,细节见代码。
查询就直接查了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
#define gc getchar
template<class T> void read(T &x) {
char c = ' '; x = 0; int f = 1;
while(c != '-' && (c < '0' || c > '9')) c = gc();
if(c == '-') f = -1, c = gc();
for(; c >= '0' && c <= '9'; c = gc()) x = x * 10 + c - '0';
}
#define pc putchar
template<class T> void write(T x) {
int d[30], d0 = 0;
if(!x) d[++ d0] = 0; else {
for(; x; x /= 10) d[++ d0] = x % 10;
}
while(d0) pc(d[d0 --] + '0');
}
const int N = 1e6 + 5;
int n, a[N];
int Q, x, y, z;
struct nod {
int a[30], b[30];
void add(int x, int y) {
fd(i, 29, 0) if(x >> i & 1) {
if(a[i]) {
if(y > b[i]) {
swap(x, a[i]);
swap(y, b[i]);
x ^= a[i];
} else {
x ^= a[i];
}
} else {
a[i] = x, b[i] = y;
break;
}
}
}
int qry(int x, int L) {
fd(i, 29, 0) if(a[i]) {
if(!(x >> i & 1) && L <= b[i]) {
x ^= a[i];
}
}
return x;
}
} b[N];
int main() {
scanf("%d", &n);
fo(i, 1, n) {
read(a[i]);
b[i] = b[i - 1];
b[i].add(a[i], i);
}
scanf("%d", &Q);
fo(ii, 1, Q) {
read(x); read(y); read(z);
write(b[y].qry(z, x));
pc('\n');
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址