[Wannafly挑战赛14 E 无效位置]线性基合并
分类:math
线性基
1. 题目链接
2. 题意描述
给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值。
输入描述:
第一行读入一个正整数
(1<=n<=105)
(
1
<=
n
<=
10
5
)
第二行读入n个正整数,第i个表示a[i]
(0<=a[i]<=109)
(
0
<=
a
[
i
]
<=
10
9
)
第三行读入n个正整数,第i个表示x[i]即第i次操作的位置,保证x[i]互不相同。
输出描述:
输出n行答案
输入
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
3. 解题思路
求集合中的最大异或和,首先想到线性基。
然后,离线答案,按照数组
x[]
x
[
]
逆序加入元素,合并线性基区间,一边插入、合并一边统计答案。
这样做的原因是,两个线性基合并一次的复杂度是
O(64∗64)
O
(
64
∗
64
)
,,但是线性基删除元素好像并不是很方便。
题意要弄清,,,题意说的是每个元素删掉,,,那么区间需要拆分成两个区间。。盯着样例看了半天。。
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
const int inf = 0x3f3f3f3f;
const long long infl = 0x3f3f3f3f3f3f3f3fLL;
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }
const int MAXN = 100005;
long long n, a[MAXN], x[MAXN], b[MAXN];
long long base[MAXN][64];
long long ans[MAXN];
int le[MAXN], ri[MAXN];
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
while (~scanf("%lld", &n)) {
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%lld", &x[i]);
}
memset(le, -1, sizeof(le));
memset(ri, -1, sizeof(ri));
for (int i = 1; i <= n; ++i) {
b[i] = a[x[i]];
}
reverse(b + 1, b + n + 1);
memset(base, 0, sizeof(base));
for (int i = 1; i <= n ; ++i) {
int pos = x[n - i + 1], left = pos, right = pos;
if (le[pos - 1] != -1) left = le[pos - 1];
if (ri[pos + 1] != -1) right = ri[pos + 1];
le[pos] = left, ri[pos] = right;
ri[left] = right, le[right] = left;
for (int j = 62; j >= 0; --j) {
int dig = b[i] >> j & 1LL;
if (dig == 0) continue;
if (!base[left][j]) {
base[left][j] = b[i];
break;
}
b[i] ^= base[left][j];
}
for (int k = 62; k >= 0; --k) {
for (int j = 62; j >= 0; --j) {
int dig = base[pos + 1][k] >> j & 1LL;
if (dig == 0) continue;
if (!base[left][j]) {
base[left][j] = base[pos + 1][k];
break;
}
base[pos + 1][k] ^= base[left][j];
}
}
ans[i] = 0;
for (int j = 62; j >= 0; --j) {
umax(ans[i], ans[i] ^ base[left][j]);
}
umax(ans[i], ans[i - 1]);
}
reverse(ans + 1, ans + n + 1);
for (int i = 1; i <= n; ++i) {
printf("%lld\n", ans[i]);
}
}
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}