传送门
题目大意:
给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值
思路: 首先我们应该想n个数中选择一些数异或起来最大怎么做? 这个用线性基可以做到.(不懂的自行百度), 在就是我们对于一个无效位置时很难控制我们在选的时候不选它, 所以我们逆向思考. 每次让一个位置无效相当于我们在可以选择的数中加了一个新的数, 也就是我们不断的合并两个线性基, 这样做就没有无效位置这个限制了… 然后连接的时候用并查集维护下. 其实这也是并查集中的逆向思考, 将集合的断开逆向变成合并两个集合……
AC Code
const int maxn = 1e5+5;
struct L_B {
ll d[65], p[65];
int cnt;
void init() {
Fill(d, 0); Fill(p, 0);
cnt = 0;
} // 1e18以内的数都适用.
bool Insert(ll val) {
for (int i = 60 ; i >= 0 ; i --) {
if (val & (1ll << i)) {
if (!d[i]) {
d[i]=val;
break;
}
val^=d[i];
}
}
return val > 0;
// 可判断val是否存在于线性基当中.
}
ll query_max() {
ll res = 0;
for (int i = 60 ; i >= 0 ; i --) {
if ((res^d[i]) > res) res ^= d[i];
}
return res;
}
ll query_min() {
for (int i = 0 ; i <= 60 ; i ++) {
if (d[i]) return d[i];
}
return 0;
}
void rebuild() { // 用于求第k小值.需要先进行独立预处理
for (int i = 60 ; i >= 0 ; i --) {
for (int j = i-1 ; j >= 0 ; j --) {
if (d[i] & (1ll<<j)) d[i] ^= d[j];
}
}
for (int i = 0 ; i <= 60 ; i ++) {
if (d[i]) p[cnt++]=d[i];
}
}
ll kthquery(ll k) {
ll res = 0;
if (k >= (1ll << cnt)) return -1;
for (int i = 60 ; i >= 0 ; i --) {
if (k & (1LL<<i)) res ^= p[i];
}
return res;
}
void Merge(const L_B &b) {
for (int i = 60 ; i >= 0 ; i --)
if (b.d[i]) Insert(b.d[i]);
}
}e[maxn];
int a[maxn], q[maxn], ans[maxn];
int n;
int fa[maxn], r[maxn];
int vis[maxn];
void init() {
for (int i = 1 ; i <= n ; i ++) {
fa[i] = i;
}
}
int Find(int x) {
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
void Un(int x, int y) {
int fx = Find(x);
int fy = Find(y);
if (fx == fy) return ;
if (fx < fy) swap(fx, fy);
fa[fx] = fy;
}
void solve()
{
scanf("%d", &n);
for (int i = 1 ; i <= n ; i ++) {
scanf("%d", &a[i]);
}
for (int i = 1 ; i <= n ; i ++ ) {
scanf("%d", &q[i]);
}
ll res = 0; init();
for (int i = n ; i >= 1 ; i --) {
e[q[i]].Insert(a[q[i]]);
vis[q[i]] = 1;
if (vis[q[i]+1]) {
int f1 = Find(q[i]+1);
Un(q[i], f1);
e[q[i]].Merge(e[f1]);
}
if (vis[q[i]-1]) {
int f2 = Find(q[i]-1);
Un(f2, q[i]);
e[f2].Merge(e[q[i]]);
}
res = max(res, e[Find(q[i])].query_max());
ans[i] = res;
}
for (int i = 1 ; i <= n ; i ++) {
printf("%d\n", ans[i]);
}
}