CF1100F Ivan and Burgers
题面:
题面翻译
给一个长为 n n n 的序列, q q q 次询问,问从 a l , a l + 1 , ⋯ , a r a_l,a_{l+1},\cdots,a_r al,al+1,⋯,ar 中选若干个数,异或和最大为多少。
1 ≤ n , q ≤ 5 × 1 0 5 1\le n,q\le 5\times 10^5 1≤n,q≤5×105, 0 ≤ c i ≤ 1 0 6 0\le c_i\le 10^6 0≤ci≤106。
样例 #1
样例输入 #1
4 7 2 3 4 3 1 4 2 3 1 3
样例输出 #1
7 3 7
样例 #2
样例输入 #2
5 12 14 23 13 7 15 1 1 1 2 1 3 1 4 1 5 2 2 2 3 2 4 2 5 3 3 3 4 3 5 4 4 4 5 5 5
样例输出 #2
12 14 27 27 31 14 25 26 30 23 26 29 13 13 7
区间查询最大异或和(前缀和线性基)
类似于 可持久化线段树,读者可以类比
我们需要记录每个数位被数占领的时间和数值,
我们插入一个数,就建立一个新的版本,其的内容是复制上一个版本(这里是完全赋值,不是可持久化线段树的直接接上),
然后我们考虑插入数,如果有数位可以填入,就填入;如果有的数位填入的时间太早,我们考虑用这个数替换,然后用被替换的数继续做线性基
为什么要替换呢?因为我们记录每个数占领的时间,当我们询问 ( l , r ) (l,r) (l,r) 时,对于版本 r r r,有效的数需要满足 t i m e i ≥ l time_{i} \geq l timei≥l。
而这个位置不考虑插入时间时,可能有多个数字可以胜任,但是考虑插入时间后,其中能胜任的只有 t i m e i ≥ l time_{i} \geq l timei≥l,其中最保险的自然是 t i m e i max time_{i\max} timeimax。
如果 t i m e i max time_{i\max} timeimax 都无法胜任,那么 插入时间为 r r r 之前的没有数字可以胜任,这样构造的答案一定合法。
大体思路就是这样,结合代码再思考应该就能理解。
AC-code:
#include<bits/stdc++.h>
using namespace std;
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 5e5 + 5;
int p[N][31],pos[N][31],n,m;
void insert(int x,int id) {
for(int i = 0;i<=30;i++) {
p[id][i] = p[id - 1][i];
pos[id][i] = pos[id - 1][i];
}
int P = id;
for(int i = 30;i >= 0;i--) {
if(x >> i & 1) {
// if(!p[id][i]) {
// p[id][i] = x;
// pos[id][i] = P;
// break;
// }
if(pos[id][i] < P)
swap(p[id][i],x),swap(pos[id][i],P);
x ^= p[id][i];
}
}
}
int query(int l,int r) {
int ans = 0;
for(int i = 30;i >= 0;i--) {
if(pos[r][i] >= l)
ans = max(ans,ans ^ p[r][i]);
}
return ans;
}
signed main() {
n = rd();
for(int i = 1;i<=n;i++) {
int x = rd();
insert(x,i);
}
m = rd();
while(m--) {
int l = rd(),r = rd();
wt(query(l,r));putchar('\n');
}
return 0;
}