CodeForces - 1100F - Ivan and Burgers
题意
- 给定一个长度为n的数列. 然后有q次查询,查询[L, R]区间中的某个子集异或和最大。
思路
- 我们定义 为 的线性基,并且这个线性基区别于平常从左往右插入,这个是从右往左插。
- 于是我们查询 某些向量异或和最大时,就可以完美避开前 向量的影响。直接遍历线性基 ,如果插入向量的位置在 范围内,那么就取异或最大咯~,否则直接舍掉
如何保证我们所取的向量在 中呢?
- 这时候我们就需要另外一个数组 表示 区间满足上述“从右往左插入向量”条件的线性基向量的位置。
- 这个数组在我们构建前缀线性基时也有重要作用!!!首先我们无论是 还是 在开始的时候都需要继承 和 . 这里数组 的作用就是更新当前线性基的 为最靠右的向量。
插入向量的代码
void add(int x, int R)
{
int id = R;
for(int i = maxBit - 1; i >= 0; -- i ) p[R][i] = p[R - 1][i], pos[R][i] = pos[R - 1][i];
for(int i = maxBit - 1; i >= 0; -- i )
{
if(x >> i & 1)
{
if(!p[R][i]) { p[R][i] = x; pos[R][i] = id; break; }
if(pos[R][i] < id) { swap(p[R][i], x); swap(pos[R][i], id); }
x ^= p[R][i];
}
}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int maxN = 500005;
const int maxBit = 21;
int n, c[maxN];
int p[maxN][maxBit];
int pos[maxN][maxBit];
void add(int x, int R)
{
int id = R;
for(int i = maxBit - 1; i >= 0; -- i ) p[R][i] = p[R - 1][i], pos[R][i] = pos[R - 1][i];
for(int i = maxBit - 1; i >= 0; -- i )
{
if(x >> i & 1)
{
if(!p[R][i]) { p[R][i] = x; pos[R][i] = id; break; }
if(pos[R][i] < id) { swap(p[R][i], x); swap(pos[R][i], id); }
x ^= p[R][i];
}
}
}
int main()
{
n = read();
for(int i = 1; i <= n; ++ i )
{
c[i] = read();
add(c[i], i);
}
int QAQ; QAQ = read();
while(QAQ -- )
{
int l, r; l = read(); r = read();
int ans = 0;
for(int i = maxBit - 1; i >= 0; -- i )
if(pos[r][i] >= l)
ans = max(ans, ans ^ p[r][i]);
cout << ans << endl;
}
return 0;
}