[Wannafly挑战赛14 E 无效位置]线性基合并

[Wannafly挑战赛14 E 无效位置]线性基合并

分类:math 线性基

1. 题目链接

[Wannafly挑战赛14 E 无效位置]

2. 题意描述

给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值。

输入描述:
第一行读入一个正整数 ( 1 <= n <= 10 5 )
第二行读入n个正整数,第i个表示a[i] ( 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 [ ] 逆序加入元素,合并线性基区间,一边插入、合并一边统计答案。
这样做的原因是,两个线性基合并一次的复杂度是 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;
}

猜你喜欢

转载自blog.csdn.net/ACMore_Xiong/article/details/80024917