P5283 异或粽子

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;
}
原文地址:https://www.cnblogs.com/suxxsfe/p/13817021.html