BZOJ 3689 异或 Trie木+堆

标题效果:特定n的数量,这种需求n数22 XOR的值前者k少

首先,我们建立了一个二进制的所有数字Trie木,您可以使用Trie木size域检查出一些其他的数字XOR值首先k少

然后,我们要保持一个堆。其他XOR的整数值首先2增加堆(第一小是自己异或自己。不在题目要求范围内)。当取出一个数异或值的第k小后,将第k+1小增加堆

一个异或值会被两个数分别取出一次。所以取出奇数次时输出,取2*k次就可以

时间复杂度O(nlogn)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef pair<int, pair<int,int> > abcd;
struct Trie{
	int siz;
	Trie *son[2];
	Trie();
}*null=new Trie,*root=null;
Trie :: Trie()
{
	siz=0;
	son[0]=son[1]=null;
}
int n,a[M];
abcd heap[M];
int top;
void Push(abcd x)
{
	heap[++top]=x;
	int t=top;
	while( t>1 && heap[t]<heap[t>>1] )
		swap(heap[t],heap[t>>1]),t>>=1;
}
void Pop()
{
	heap[1]=heap[top--];
	int t=2;
	while( t<=top )
	{
		if( t<top && heap[t+1]<heap[t] )
			++t;
		if( heap[t]<heap[t>>1] )
			swap(heap[t],heap[t>>1]),t<<=1;
		else
			break;
	}
}
void Insert(Trie*&p,int x,int pos)
{
	if(p==null)
		p=new Trie();
	p->siz++;
	if(!pos)
		return ;
	Insert(p->son[x&pos?

1:0],x,pos>>1);
}
int Get_Kth(Trie*p,int x,int pos,int k)
{
	if(!pos)
		return 0;
	if(k<=p->son[x&pos?1:0]->siz)
		return Get_Kth(p->son[x&pos?1:0],x,pos>>1,k);
	else
		return Get_Kth(p->son[x&pos?0:1],x,pos>>1,k-p->son[x&pos?

1:0]->siz)+pos;
}
int main()
{
	int i,k;
	cin>>n>>k;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]),Insert(root,a[i],1<<30);
	for(i=1;i<=n;i++)
		Push( make_pair( Get_Kth(root,a[i],1<<30,2) , make_pair(i,2) ) );
	for(i=1;i<=k<<1;i++)
	{
		abcd temp=heap[1];Pop();
		if(i&1)
			printf("%d ",temp.first);
		if(temp.second.second!=n)
		{
			int x=temp.second.first;
			int y=temp.second.second;
			Push( make_pair( Get_Kth(root,a[x],1<<30,y+1) , make_pair(x,y+1) ) );
		}
	}
}

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-09-30 15:55:37

BZOJ 3689 异或 Trie木+堆的相关文章

BZOJ 3689: 异或之

二次联通门 : BZOJ 3689: 异或之 /* BZOJ 3689: 异或之 zz题 */ #include <cstdio> #include <iostream> #include <queue> #define rg register struct IO { static const int BUF = 12323233; char p[BUF], *s, *t, e[BUF]; int a[25]; IO () : s (p), t (e) { fread

BZOJ 3689 异或之 Trie树+堆

题目大意:给定n个数,求这n个数两两异或的值中的前k小 首先我们对所有数字建立二进制Trie树,可以利用Trie树上的size域查询出一个数与其它数异或值的第k小 然后我们维护一个堆,将所有数与其它异或值的第2小加入堆(第一小是自己异或自己,不在题目要求范围内),当取出一个数异或值的第k小后,将第k+1小加入堆 一个异或值会被两个数分别取出一次,所以取出奇数次时输出,取2*k次即可 时间复杂度O(nlogn) #include<cstdio> #include<cstring> #

【CodeForces】947 C. Perfect Security 异或Trie

[题目]C. Perfect Security [题意]给定长度为n的非负整数数组A和数组B,要求将数组B重排列使得A[i]^B[i]的字典序最小.n<=3*10^5,time=3.5s. [算法]异或Trie [题解]对一个数组O(n log n)建立异或Trie,就能O(log n)判断任意一个数在这个数组中异或值最大的数. 所以对B建异或Trie(每个数字从高二进制位开始插入),然后数组A依次在Trie上跑,从上到下尽量跑向相同数字边,这样得到字典序最小,路径中顺便删除标记. 复杂度O(n

CF 979D Kuro and GCD and XOR and SUM(异或 Trie)

CF 979D Kuro and GCD and XOR and SUM(异或 Trie) 给出q(<=1e5)个操作.操作分两种,一种是插入一个数u(<=1e5),另一种是给出三个数x,k,s(<=1e5),求当前所有数中满足,k|v,x+v<=s,且\(x\oplus v\)最大的v. 做法好神啊.关于异或的问题有一种常见做法,就是利用01trie来查找在一堆数里面,那个数与x的异或值最大.这道题就是这个思路.如果去掉k必须整除v这个条件,那么就转化成了上一个问题(只不过有最大

BZOJ 4260: Codechef REBXOR( trie )

求出前缀和, 那么以第x个元素结尾的最大异或值是max(sumx^sump)(1≤p<x), 用trie加速. 后缀同理, 然后扫一遍就OK了.时间复杂度O(31N) ----------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<cctype>

XJOI 异或 (Trie树)

这题对我来说真是一块大蛋糕,又是一座大山 大蛋糕是因为算法很好胡 大山是因为我实在是太菜 然后我就在考场上续了两个小时 /-------------------------------------------/ 这题算法不算难想,但对我来说挺难打 1.将ai拆成二进制,由高位到低位加入Trie树,不足的补前导0,每个节点的ans统计子树中有多少个值 2.读入区间l,r拆成区间1-r+1,1-l处理 3.search时统计小于limit的数量 4.如果pos的一个子树内异或x最大值之差小于limi

BZOJ 1455: 罗马游戏 [可并堆]

1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1715  Solved: 718[Submit][Status][Discuss] Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的

BZOJ 1029 建筑抢修(贪心堆)

原题代号:BZOJ 1029 原题描述: 建筑抢修 小刚在玩JSOI提供的一个称之为"建筑抢修"的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏.现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间.同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑.如果某个建筑在一段时间之内没有完全修理完毕,这个建

bzoj 1150&amp;2151&amp;2288(双向链表+堆)(贪心)

经典模型:在n个点中选k个点,要求两两不相邻,且总权值最大/最小. 做法:用双向链表串起来,把所有点丢进堆里,选择一个点的时候把它左右两个点从双向链表和堆中去除,然后把这个点的权值加进ans,出堆后改为左右两边的权值-当前权值重新入堆,重复k次,ans即为答案 原理:左右两边的权值-当前权值相当于这个点不选,改为选左右两边的点,并且多选了一个点,重复k次后必然取到k个点 三道同类型题 bzoj1150:显然一段网线肯定接在相邻的两个点,于是把相邻的点的距离求出来,问题就变成经典模型了 #incl