链接:
https://www.nowcoder.com/acm/contest/81/E
来源:牛客网
来源:牛客网
题目描述
给一个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
题解:由于每次顺序已知,所以我们从后往前来,如果当前这个位置的前面或者后面的数,已经存在,则可以合并区间,进行线型基求解最大值。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
const int N = 30;
int par[maxn];
int num[maxn];
int pos[maxn];
int res[maxn];
int find(int x)
{
return x == par[x] ? x : par[x] = find(par[x]);
}
struct linearBase
{
int d[N+1];
void init() {
memset(d,0,sizeof(d));
}
void insert(int val) {
for(int i = N;i >= 0;i --) {
if(val&(1<<i)) {
if(!d[i]) {
d[i] = val;
break;
}
val ^= d[i];
}
}
}
int query_max() {
int res = 0;
for(int i = N;i >= 0;i --) res = max(res, res ^ d[i]);
return res;
}
void merge(linearBase& n) {
for(int i = N;i >= 0;i --) {
if(n.d[i]) insert(n.d[i]);
}
}
}Base[maxn];
int main()
{
int n;
scanf("%d", &n);
for(int i = 1;i <= n;i ++) scanf("%d", &num[i]);
for(int i = 1;i <= n;i ++) scanf("%d", &pos[i]);
for(int now=0,i = n;i >= 1;i --) {
int p = pos[i];
par[p] = p;
Base[p].insert(num[p]);
if(par[p-1]) {
int fa = find(p-1);
Base[fa].merge(Base[p]);
par[p] = fa;
}
if(par[p+1]) {
int fa = find(p+1);
int ff = find(p);
Base[fa].merge(Base[ff]);
par[ff] = fa;
}
now = max(now, Base[find(p)].query_max());
res[i] = now;
}
// for(int i = 1;i <= n;i ++) printf("%d ",find(i));puts("");
for(int i = 1;i <= n;i ++) printf("%d\n", res[i]);
return 0;
}