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;
}