「Bzoj 5495」「十二省联考2019」异或粽子 (可持久化01Trie + 堆)

BZOJ 5495
题意:求异或和前$k$大的区间的和。

类似超级钢琴做法,见bzoj 5495
那题查询最大值用的st表,这里是异或区间最大所以想到可持久化01Trie维护即可。

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;

namespace flyinthesky {

    const int MAXN = 500000 + 5, LEN = 34;

    int n, k;
    LL a[MAXN], s[MAXN];
    int rt[MAXN], ch[MAXN * 40][2], end[MAXN * 40], sz;
    int gg[40], hh[40];

    struct data {
        int l, r, x, y;
        bool operator < (const data &rhs) const {
            return (s[r] ^ s[l - 1]) < (s[rhs.r] ^ s[rhs.l - 1]);    
        }
    };
    priority_queue<data > q;

    void fj(LL v) {
        int len = 0; LL tmp = v; ms(gg, 0);
        do {gg[++len] = tmp & 1, tmp >>= 1;} while (tmp);
    }
    void ins(int pre, int now, int i, int ith) {
        if (i == 0) {end[now] = ith; return ;}
        int c = gg[i];
        ch[now][c] = ++sz, ch[now][c ^ 1] = ch[pre][c ^ 1];
        ins(ch[pre][c], ch[now][c], i - 1, ith);
        end[now] = max(max(end[now], end[ch[now][0]]), end[ch[now][1]]);
    }
    int query(int now, int l) {
        for (int i = LEN; i; --i) {
            int c = gg[i];
            if (end[ch[now][c ^ 1]] >= l && ch[now][c ^ 1]) {
                hh[i] = 1, now = ch[now][c ^ 1];
            } else hh[i] = 0, now = ch[now][c];
        }
        return end[now];
    }

    void clean() {
        sz = 0, ms(rt, 0), ms(ch, 0), ms(end, 0);
    }
    int solve() {

        clean();
        cin >> n >> k;
        for (int i = 1; i <= n; ++i) {
            scanf("%lld", &a[i]);
            s[i] = s[i - 1] ^ a[i];

            fj(s[i]), ins(rt[i - 1], rt[i] = ++sz, LEN, i);
        }
        for (int l = 1; l <= n; ++l) {
            fj(s[l - 1]);
            int id = query(rt[n], l);
            LL bs = 1, res = 0;
            for (int i = 1; i <= LEN; ++i) res += bs * hh[i], bs *= 2ll;
            q.push((data){l, id, l, n});
        }

        LL ans = 0;
        for (int i = 1; i <= k; ++i) {
            data p = q.top(); q.pop();
            ans += (s[p.l - 1] ^ s[p.r]);

            if (p.x <= p.r - 1) {
                fj(s[p.l - 1]);
                int id = query(rt[p.r - 1], p.x);
                LL bs = 1, res = 0;
                for (int j = 1; j <= LEN; ++j) res += bs * hh[j], bs *= 2ll;
                q.push((data){p.l, id, p.x, p.r - 1});
            } 
            if (p.r + 1 <= p.y) {
                fj(s[p.l - 1]);
                int id = query(rt[p.y], p.r + 1);
                LL bs = 1, res = 0;
                for (int j = 1; j <= LEN; ++j) res += bs * hh[j], bs *= 2ll;
                q.push((data){p.l, id, p.r + 1, p.y});
            }

        }

        cout << ans;

        return 0;
    } 
}
int main() {
    flyinthesky::solve();
    return 0;
}
/*
5 3
5 4 2 3 1
*/
------ 本文结束 ------