把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5283】[十二省联考2019] 异或粽子(可持久化Trie树+堆)

点此看题面

大致题意: 求前\(k\)大的区间异或和之和。

可持久化\(Trie\)

之前做过一些可持久化\(Trie\)树题,结果说到底还是主席树。

终于,碰到一道真·可持久化\(Trie\)的题目。

其实它的实现与主席树也是类似的。

大致思路

首先,我们统计一遍前缀异或和。

然后,我们根据前缀异或和建一棵可持久化\(Trie\)树。

接下来最核心的来了:

我们先求出以每个点为右端点所能得到的最大异或和,这可以在\(Trie\)树上查询得到(和普通的\(Trie\)树是一样的)。

然后,把这些值连同该右端点全扔入大根堆里。

每次,我们取出堆顶,统计答案后求出以该点为右端点所能得到的次大值,然后重新扔入堆里。如果再取到该右端点,就是次次大值、次次次大值,以此类推。

那么如何求次大值呢?

没关系,反正我们本来就是可持久化\(Trie\)树,直接复制该点的\(Trie\)树并将求出的最大值所对应的数在树上删去即可。

这种方法的复杂度应该是\(O((n+k)log\ Max\ a_i)\),但我写得弱了一点,变成了\(O((2n+k)log\ Max\ a_i)\)。虽然很好改,但我懒得改了。。。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define RU Reg unsigned
#define Con const
#define CI Con int&
#define CU Con unsigned&
#define I inline
#define W while
#define N 500000
#define K 200000
#define mp make_pair
#define fir first
#define sec second
using namespace std;
int n,k,p[N+5];unsigned a[N+5];typedef pair<unsigned,int> Pr;
priority_queue<Pr> q;
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		char c,*A,*B,FI[FS];
	public:
		I FastIO() {A=B=FI;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
		#undef D
}F;
class PersistentTrie//可持久化Trie树
{
	private:
		#define SZ ((N<<1)+K+1)
		#define Log 33
		int tot,Rt[N+5];struct node {int Sz,S[2];}O[SZ*Log+5];
		I void upt(int& rt1,RI rt2,CU x,CI t,CI D)//修改
		{
			if((O[rt1=++tot]=O[rt2]).Sz+=t,!~D) return;//复制节点,更新size
			RI d=(x>>D)&1;upt(O[rt1].S[d],O[rt2].S[d],x,t,D-1);//处理子节点
		}
		I unsigned qry(int& rt,CI x,CI D)//询问与x的最大异或和
		{
			if(!~D) return 0;RI d=(x>>D)&1;
			return O[O[rt].S[d^1]].Sz?qry(O[rt].S[d^1],x,D-1)|(1<<D):qry(O[rt].S[d],x,D-1);//能使这一位为1就必使其为1,否则使其为0
		}
	public:
		I PersistentTrie() {tot=1,Update(0,0,0,1);}
		I void Update(CI v1,CI v2,CU x,CI t) {upt(Rt[v1],Rt[v2],x,t,31);}
		I unsigned Query(CI v) {RU t=qry(Rt[v],a[v],31);return Update(v,v,a[v]^t,-1),t;}//询问,为避免计算多次贡献将其删去
}P;
int main()
{
	RI i;Pr t;Reg long long ans=0;
	for(F.read(n,k),i=1;i<=n;++i) F.read(a[p[i]=i]),a[i]^=a[i-1],P.Update(i,i-1,a[i],1);//初始化建树
	for(i=1;i<=n;++i) q.push(mp(P.Query(i),i));//询问然后扔入堆中
	for(i=1;i<=k;++i) t=q.top(),q.pop(),ans+=t.fir,//取出堆顶,统计答案
		--p[t.sec]&&(q.push(mp(P.Query(t.sec),t.sec)),0);//将次大值扔入堆中
	return printf("%lld",ans),0;//输出答案
}
posted @ 2019-04-16 07:59  TheLostWeak  阅读(220)  评论(0编辑  收藏  举报