给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值。
输入描述:
第一行读入一个正整数(1 <= n <= 105)
第二行读入n个正整数,第i个表示a[i](0<= a[i] <= 109)
第三行读入n个正整数,第i个表示x[i]即第i次操作的位置,保证x[i]互不相同。
输出描述:
输出n行答案
示例1
输入
10 169 816 709 896 58 490 97 254 99 796 4 2 3 10 5 6 1 8 9 7
输出
1023 994 994 994 490 490 254 254 99 97
题意 : 每次让一个位置得数失效,求解连续区间上异或值最大得是多少?
思路分析 : 每次让一个位置失效,那么这个问题就可以逆向去考虑,每次加一个数,这个总比删除操作好处理,用并查集就可以,然后就是一个在套一个线性基就可以
代码示例 :
#define ll long long
const int maxn = 1e5+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
int n;
int pre[maxn], pos[maxn];
int f[maxn];
int val[maxn][40];
int an[maxn];
int fid(int x){
if (x != f[x]) f[x] = fid(f[x]);
return f[x];
}
void insert(int b[], int x){
for(int i = 30; i >= 0; i--){
if (x>>i&1){
if (!b[i]) {b[i] = x; break;}
else x ^= b[i];
}
}
}
void unit(int p1, int p2){
int x = fid(p1), y = fid(p2);
for(int i = 0; i <= 30; i++){
if (val[y][i]) insert(val[x], val[y][i]);
}
f[y] = x;
}
int solve(int p){
int ans = 0;
for(int i = 30; i >= 0; i--){
if ((ans^val[p][i]) > ans) {
ans ^= val[p][i];
}
}
return ans;
}
int main() {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
cin >> n;
for(int i = 1; i <= n; i++) scanf("%d", &pre[i]);
for(int i = 1; i <= n; i++) scanf("%d", &pos[i]);
memset(f, 0, sizeof(f));
int ans = 0;
for(int i = n; i >= 1; i--){
int x = pos[i]; // 位置
f[x] = x;
insert(val[x], pre[x]);
if (f[x-1]) unit(x, x-1);
if (f[x+1]) unit(x, x+1);
ans = max(ans, solve(x));
an[i] = ans;
}
for(int i = 1; i <= n; i++) printf("%d\n", an[i]);
return 0;
}