链接:
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; }