[十二省联考2019] 异或粽子 - 可持久化Trie,堆

\(n\) 元数列的 \(k\) 个不同的子区间使得各个子区间异或和之和最大。

Solution

(差点又看错题了)

做个前缀和,于是转化成求序列异或和最大的 \(k\) 个数对

建一棵可持久化 0-1 Trie,这样我们就可以 \(O(log n)\) 求出对于某个右端点,它的所有可能答案中,第 \(k\) 大的答案

然后利用堆来维护答案。我们先把对每一个右端点,第 \(1\) 大的答案插入堆。然后循环弹出。每次弹出一个,如果它是 \(u\) 这个右端点对应的第 \(v\) 大的答案,我们就计算出 \(u\) 这个右端点对应的第 \(v+1\) 大的答案(如果存在的话)并且把它插入堆,然后继续。

#include 
using namespace std;

#define int long long

const int N = 1000005;

namespace trie {
    int ind,ch[N*40][2],siz[N*40],root[N*40];
    void insert(int id,int x) {
        root[id]=++ind;
        ch[ind][0]=ch[root[id-1]][0];
        ch[ind][1]=ch[root[id-1]][1];
        siz[ind]=siz[root[id-1]]+1;
        int p=ind;
        for(int i=39;i>=0;--i) {
            int t=(x>>i)&1;
            ++ind;
            ch[ind][0]=ch[ch[p][t]][0];
            ch[ind][1]=ch[ch[p][t]][1];
            siz[ind]=siz[ch[p][t]]+1;
            ch[p][t]=ind;
            p=ind;
        }
    }
    int query(int id,int x,int k) {
        int p=root[id],ans=0;
        for(int i=39;i>=0;--i) {
            int t=(x>>i)&1;
            if(siz[ch[p][t^1]]>=k) {
                p=ch[p][t^1];
                ans|=1ll< q;
int n,k,a[N],ans;

signed main() {
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++) {
        scanf("%lld",&a[i]);
        a[i]^=a[i-1];
    }
    for(int i=0;i<=n;i++) {
        trie::insert(i,a[i]);
    }
    for(int i=1;i<=n;i++) {
        q.push((pii){trie::query(i-1,a[i],1),i,1});
        //cout<

你可能感兴趣的:([十二省联考2019] 异或粽子 - 可持久化Trie,堆)