【BZOJ3689】异或之 堆+可持久化Trie树

【BZOJ3689】异或之

Description

给定n个非负整数A[1], A[2], ……, A[n]。
对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数。求这些数(不包含A[i])中前k小的数。
注:xor对应于pascal中的“xor”,C++中的“^”。

Input

第一行2个正整数 n,k,如题所述。
以下n行,每行一个非负整数表示A[i]。

Output

共一行k个数,表示前k小的数。

Sample Input

4 5
1
1
3
4

Sample Output

0 2 2 5 5

HINT

【样例解释】
1 xor 1 = 0 (A[1] xor A[2])
1 xor 3 = 2 (A[1] xor A[3])
1 xor 4 = 5 (A[1] xor A[4])
1 xor 3 = 2 (A[2] xor A[3])
1 xor 4 = 5 (A[2] xor A[4])
3 xor 4 = 7 (A[3] xor A[4])
前5小的数:0 2 2 5 5
【数据范围】
 对于100%的数据,2 <= n <= 100000; 1 <= k <= min{250000, n*(n-1)/2};
        0 <= A[i] < 2^31

题解:这不就是BZOJ2006超级钢琴吗?没做过的先去做那道题。

然后这题把超级钢琴中的ST表换成可持久化Trie树就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <utility>
#define mp(A,B,C,D) make_pair(make_pair(A,B),make_pair(C,D))
using namespace std;
typedef pair<int,int> pii;
priority_queue<pair<pii,pii> > pq;
const int maxn=100010;
int n,m,tot;
int ch[maxn*35][2],rt[maxn],siz[maxn*32],org[maxn*32],v[maxn];
void insert(int x,int y,int num)
{
	int i,d,u;
	u=rt[y]=++tot;
	for(i=1<<30;i;i>>=1)
	{
		d=(num&i)>0;
		ch[u][d]=++tot,ch[u][d^1]=ch[x][d^1],u=ch[u][d],x=ch[x][d],siz[u]=siz[x]+1;
	}
	org[u]=y;
}
int query(int x,int y,int num)
{
	int ret=0,i,d;
	for(i=1<<30;i;i>>=1)
	{
		d=(num&i)>0;
		if(siz[ch[y][d]]==siz[ch[x][d]])	d^=1;
		x=ch[x][d],y=ch[y][d];
	}
	return org[y];
}
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd();
	int i,a,b,c,x,y;
	for(i=1;i<=n;i++)	v[i]=rd(),insert(rt[i-1],i,v[i]);
	for(i=2;i<=n;i++)	pq.push(mp(-(v[i]^v[query(0,rt[i-1],v[i])]),i,1,i-1));
	pii t1,t2;
	for(i=1;i<=m;i++)
	{
		if(i!=1)	printf(" ");
		t1=pq.top().first,t2=pq.top().second,pq.pop();
		printf("%d",-t1.first),x=t1.second,a=t2.first,b=t2.second;
		y=query(rt[a-1],rt[b],v[x]);
		if(y>a)	pq.push(mp(-(v[x]^v[query(rt[a-1],rt[y-1],v[x])]),x,a,y-1));
		if(y<b)	pq.push(mp(-(v[x]^v[query(rt[y],rt[b],v[x])]),x,y+1,b));
	}
	return 0;
}
时间: 2024-08-04 08:46:04

【BZOJ3689】异或之 堆+可持久化Trie树的相关文章

bzoj 3261: 最大异或和 (可持久化trie树)

3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Description 给定一个非负整数序列 {a},初始长度为 N.       有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. Inp

bzoj3261: 最大异或和 (可持久化trie树)

题目链接 题解 看到异或和最大就应该想到01 trie树 我们记\(S_i\)为前i项的异或和 那么我们的目的是最大化\(S_n\)^\(x\)^\(S_{j-1}\) \((l <= j <= r)\) (注意是\(j-1\), 所以l和r都要减1) \(S_n\)^\(x\)已经固定, 那么我们可以把\(S_j\)放入trie树搞 那么怎么处理区间呢? 类似主席树 记录一下\([1-i]\)每个节点被多少个数经过 那么两棵trie树相减,就得到了 \([l-r]\)这段区间的信息 然后就是

【bzoj3281】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 输入 第一行包含两个整数 N  ,M,含义如问题描述所示.   第二行包含 N个非负整数,表示初始的序列 A . 接下来 M行,每行描述一个

[bzoj3261]最大异或和[可持久化trie树]

因为要求异或和最大,所以可以考虑从高位开始,向低位枚举尽可能接近~x的值,所以以二进制位为关键字,建立可持久化trie树,根据异或和的性质,XOR_SUM{i,j}=XOR_SUM{1,j} xor XOR_SUM{1,i-1},所以查询问题也可以解决了. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <c

【BZOJ4103】[Thu Summer Camp 2015]异或运算 可持久化Trie树

[BZOJ4103][Thu Summer Camp 2015]异或运算 Description 给定长度为n的数列X={x1,x2,...,xn}和长度为m的数列Y={y1,y2,...,ym},令矩阵A中第i行第j列的值Aij=xi xor  yj,每次询问给定矩形区域i∈[u,d],j∈[l,r],找出第k大的Aij. Input 第一行包含两个正整数n,m,分别表示两个数列的长度 第二行包含n个非负整数xi 第三行包含m个非负整数yj 第四行包含一个正整数p,表示询问次数 随后p行,每行

bzoj4103异或运算 可持久化trie树

要去清华冬令营了,没找到2016年的题,就先坐一坐15年的. 因为n很小,就按照b串建可持久化trie树,a串暴力枚举. 其他的直接看代码. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; inline int read() { int x=0,f=1,ch=getchar(); while(ch<'0'||ch

BZOJ 3261 最大异或和 可持久化Trie树

题目大意:给定一个序列,提供下列操作: 1.在数组结尾插入一个数 2.给定l,r,x,求一个l<=p<=r,使x^a[p]^a[p+1]^...^a[n]最大 首先我们可以维护前缀和 然后就是使x^sum[n]^sum[p-1]最大 x^sum[n]为定值,于是用Trie树贪心即可 考虑到l-1<=p-1<=r-1,我们不能对于每个询问都建一棵Trie树,但是我们可以对于Trie数维护前缀和,建立可持久化Trie树 每个区间[l,r]的Trie树为tree[r]-tree[l-1]

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

[BZOJ3261&amp;BZOJ3166]可持久化trie树及其应用

可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系即可. tr[y].son[p xor 1]:=tr[x].son[p xor 1]; tr[y].sum:=tr[x].sum+1; 这两句要好好体会,对之后理解query过程中的语句很有帮助. if (tr[tr[x].son[p xor 1]].sum=tr[tr[x].son[p xor 1