LG5283 异或粽子

题意

共有(n)个数,选择(k)个不同的([l,r])区间,使得它们的异或和最大
$ 1 leq n leq 5 imes 10^5,k leq 2 imes 10^5$

思路

先会想到前缀异或和,这样求([l,r])区间异或和只需要用(pre[l-1]oplus pre[r])以此减少运算次数。然后由于是异或,又会想到(trie),然后想一想,好像要用可持久化!!!完了太菜了不会。
但为了偷懒,必须思考。思考过后发现,不用可持久化,([l,r])区间算([l,r],[r,l])两次,答案再除二就好了

#include <bits/stdc++.h>
using std::priority_queue;
const int N=500005;
long long trie[N<<5][2],a[N],x,ans;
int tot=1,n,k,size[N<<5];
struct note{
    int x,rk;
    long long w;
    bool operator < (const note &a)const{return w<a.w;}
};
priority_queue <note> q;
long long read(){
    long long t=0;
    char c=getchar();
    while (c<'0' || c>'9') 
    c=getchar();
    while (c>='0' && c<='9') t=t*10+c-'0',c=getchar();
    return t;
}

void add(long long x){
    int u=1;
    for (int i=31;i>=0;i--){
        int t=(x>>i)&1;
        size[u]++;
        if (!trie[u][t]) trie[u][t]=++tot;
        u=trie[u][t];
    }
    size[u]++;
}
long long query(long long x,int k){
    long long ans=0;
    int u=1;
    for (int i=31;i>=0;i--){
        int t=(x>>i)&1;
        if (trie[u][t^1] && size[trie[u][t^1]]>=k) 
        u=trie[u][t^1],ans^=1LL<<i;
        else k-=size[trie[u][t^1]],u=trie[u][t];
    }
    return ans;
}
int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++){
        x=read();
        a[i]=a[i-1]^x;
        add(a[i]);
    }
    add(0);
    for (int i=0;i<=n;i++) q.push(note{i,1,query(a[i],1)});
    for (int i=1;i<=k*2;i++){
        note t=q.top();q.pop();
        ans+=t.w;
        if (t.rk<=n) q.push(note{t.x,t.rk+1,query(a[t.x],t.rk+1)});
    }
    printf("%lld",ans/2);
} 

上海省选浪的太开心了,太菜了第二天(99)难受

* 生而自由 爱而无畏 *
原文地址:https://www.cnblogs.com/flyfeather6/p/10804744.html