【十二省联考2019】【LOJ3048】【洛谷P5283】【BZOJ5495】异或粽子(01Trie)(堆)

LOJ传送门

洛谷传送门

BZOJ传送门


解析:

这个。。。其实怎么开心怎么玩就好了。

可以只建一个01Trie,然后查询前 k ∗ 2 k*2 k2的值就行了。

也可以只建一个可持久化的,然后每个在自己的01Trie里面查询就行了。

还是挺休闲的。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
#define int unsigned int

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

using std::cout;
using std::cerr; 


cs int N=5e5+50,B=31,M=N*(B+10);
int n,k;

int rt[N],son[M][2],siz[M],tot; 

inline void insert0(){
	rt[0]=++tot;
	siz[tot]=1;
	int now=tot;
	for(int re i=B;~i;--i){
		son[now][0]=++tot;
		now=tot;
		siz[now]=1;
	}
}

inline void insert(int id,int val){
	int pre=rt[id-1];
	int now=rt[id]=++tot;
	siz[now]=siz[pre]+1;
	for(int re i=B;~i;--i){
		bool f=(val>>i)&1;
		son[now][!f]=son[pre][!f];
		son[now][f]=++tot;
		siz[tot]=siz[son[pre][f]]+1;
		now=son[now][f];
		pre=son[pre][f];
	}
}

inline int query(int id,int val,int k){
	int res=0;
	int now=rt[id];
	for(int re i=B;~i;--i){
		bool f=(val>>i)&1;
		if(siz[son[now][!f]]>=k)res|=1ll<<i,now=son[now][!f];
		else {
			k-=siz[son[now][!f]];
			now=son[now][f];
		}
	}
	return res;
}

typedef std::pair<int,int> pii;
#define mp std::make_pair

std::priority_queue<pii,std::vector<pii> > q;

int a[N];
int rk[N];
ll ans; 
signed main(){
	n=getint(),k=getint();
	insert0();
	for(int re i=1;i<=n;++i)insert(i,a[i]=getint()^a[i-1]);
	for(int re i=1;i<=n;++i)q.push(mp(query(i,a[i],rk[i]=1),i));
	while(k--){
		pii tmp=q.top();q.pop();
		ans+=tmp.first;
		q.push(mp(query(tmp.second,a[tmp.second],++rk[tmp.second]),tmp.second));
	}
	cout<<ans<<"\n";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值