https://www.luogu.com.cn/problem/P5283
其实并不需要可持久化,只需要不同的 trie 就行了
先把它来个异或前缀和,这样问题就转化为了求前 (k) 大的任意两数异或的和,记得要补一个 (0)
因为异或有交换律,不妨先求前 (2k) 大的和,然后答案除以二,这样就不用考虑重复的问题了
然后把每个数插入到 trie 上,这样可以 (O(log a_i)) 的求一个数与这个数列中其他数异或的第 (rank) 大的结果(考虑每一位是向和这个数在那一位相同的数字方向走,还是相异)
然后开一个堆,首先把每个数和别的数异或的最大结果插入堆中,然后每次取出最大值,假设这是某个数与其他数异或的第 (rk) 大的,那么就答案加上它,并把这个数与其他数异或第 (rk+1) 大的插入对中
另外手写对跑的真比 stl 的快得多,在不开O2的代码中大概第三左右
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN puts("")
inline long long read(){
register long long x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
int n,k;
struct node{
int id,rk;
long long num;
}heap[50000006];
int size;
struct tr{
tr *son[2];
int cnt;
}dizhi[50000006],*root,*null;
int tot;
long long a[500006];
inline void New(tr *&a){
a=&dizhi[++tot];
a->son[0]=a->son[1]=null;
}
#define MAX 33
void insert(tr *tree,long long num,int pos){
tree->cnt++;
if(pos<0) return;
int nex=(num>>pos)&1;
if(tree->son[nex]==null) New(tree->son[nex]);
insert(tree->son[nex],num,pos-1);
}
long long ask(tr *tree,long long num,int rk,int pos){
// printf("rk = %d
",rk);
if(pos<0) return 0;
int nex=((num>>pos)&1)^1;
if(tree->son[nex]->cnt>=rk) return (1ll<<pos)+ask(tree->son[nex],num,rk,pos-1);
return ask(tree->son[nex^1],num,rk-tree->son[nex]->cnt,pos-1);
}
inline int operator >=(const node &a,const node &b){return a.num>=b.num;}
inline void push(node x){
heap[++size]=x;
reg int i=size,fa;
while(i>1){
fa=i>>1;
if(heap[fa]>=heap[i]) return;
std::swap(heap[fa],heap[i]);i=fa;
}
}
inline node pop(){
node ret=heap[1];heap[1]=heap[size--];
reg int i=1,ls,rs;
while((i<<1)<=size){
ls=i<<1;rs=ls|1;
if(rs<=size&&heap[rs]>=heap[ls]) ls=rs;
if(heap[i]>=heap[ls]) break;
std::swap(heap[i],heap[ls]);i=ls;
}
return ret;
}
int main(){
n=read();k=read()*2;
null=&dizhi[0];null->son[0]=null->son[1]=null;
New(root);
insert(root,0,MAX);
for(reg int i=1;i<=n;i++){
a[i]=read()^a[i-1];
insert(root,a[i],MAX);
}
for(reg int i=0;i<=n;i++) push((node){i,1,ask(root,a[i],1,MAX)});
reg node now;long long ans=0;
while(k--){
now=pop();
ans+=now.num;
if(now.rk<n) push((node){now.id,now.rk+1,ask(root,a[now.id],now.rk+1,MAX)});
}
printf("%lld",ans>>1);
return 0;
}