【BZOJ3689】异或之(可持久化Trie树)

点此看题面

大致题意: 给定\(n\)个数,让你求两两异或和的前\(k\)小值。

双倍经验

这道题和【洛谷5283】[十二省联考2019] 异或粽子是完全一样的,甚至比那题还少一个虽说挺简单的转化。

这里就直接贴代码了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define K 250000
#define LN 30
using namespace std;
int n,k,a[N+5];
struct data
{
	int p,v;I data(CI x=0,CI y=0):p(x),v(y){}
	I bool operator > (Con data& o) Con {return v>o.v;}
};priority_queue<data,vector<data>,greater<data> > q;
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
		Tp I void write(Ty x,Con char& y) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc(y);}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class Trie
{
	private:
		int Nt,Rt[N+5];struct node {int Sz,S[2];}O[(N+K)*(LN+2)+5];
		I void U(int& x,RI y,CI v,CI k,CI d)//修改
		{
			(O[x=++Nt]=O[y]).Sz+=k;if(!~d) return;
			U(O[x].S[(v>>d)&1],O[y].S[(v>>d)&1],v,k,d-1);
		}
		I int Q(CI rt,CI v,CI d)//询问
		{
			if(!~d) return 0;RI t=(v>>d)&1;
			if(O[O[rt].S[t]].Sz) return Q(O[rt].S[t],v,d-1);//贪心选0
			return Q(O[rt].S[t^1],v,d-1)|(1<<d);
		}
	public:
		I void U(CI v,CI lst,CI x,CI y) {U(Rt[v],Rt[lst],x,y,LN);}
		I int Q(CI v,CI x) {return O[Rt[v]].Sz?Q(Rt[v],x,LN):-1;}
}T;
int main()
{
	RI i;for(F.read(n),F.read(k),i=1;i<=n;++i) F.read(a[i]),T.U(i,i-1,a[i],1);
	for(i=2;i<=n;++i) q.push(data(i,T.Q(i-1,a[i])));//初始化堆
	RI v;data t;for(i=1;i<=k;++i) t=q.top(),q.pop(),F.write(t.v," \n"[i==k]),//取出堆顶输出
		T.U(t.p-1,t.p-1,a[t.p]^t.v,-1),~(v=T.Q(t.p-1,a[t.p]))&&(q.push(data(t.p,v)),0);//找到新的最小值
	return F.clear(),0;
}

猜你喜欢

转载自www.cnblogs.com/chenxiaoran666/p/BZOJ3689.html