[Trie树] BZOJ3689: 异或之
2017-07-13 17:03
211 查看
题意
给定n个非负整数A[1], A[2], ……, A。
对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数。求这些数(不包含A[i])中前k小的数。
n<=100000
题解
有关Trie与二进制的一些运用之前完全不会,现在补一下。我们可以把所以数字从高位开始插到Trie里,根据每个节点维护的size, 就可以在上面找一个数与Trie中的n个数异或值第K大。
然后就可以对全局开一个堆,每次取出来更新即可。
#include<cstdio> #include<queue> #include<algorithm> #define Fir first #define Sec second using namespace std; const int maxn=100005; priority_queue< pair< int,pair<int,int> > > _heap; int n,K,a[maxn]; struct node{ int sz; node* ch[2]; node(node* son=NULL){ ch[0]=ch[1]=son; sz=0; } } nil,*null=&nil,*root=null; typedef node* P_node; void Insert(P_node &p,int val,int now){ if(p==null) p=new node(null); p->sz++; if(now) Insert(p->ch[(val&now)?1:0],val,now>>1); } int Kth(P_node p,int k,int val,int now){ if(!now) return 0; int t=p->ch[(val&now)?1:0]->sz; if(k<=t) return Kth(p->ch[(val&now)?1:0],k,val,now>>1); else return now+Kth(p->ch[(val&now)?0:1],k-t,val,now>>1); } int main(){ freopen("bzoj3689.in","r",stdin); freopen("bzoj3689.out","w",stdout); scanf("%d%d",&n,&K); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); Insert(root,a[i],1<<30); } for(int i=1;i<=n;i++) _heap.push(make_pair(-Kth(root,2,a[i],1<<30),make_pair(i,2))); for(int i=1;i<=2*K;i++){ pair< int,pair<int,int> > x=_heap.top(); _heap.pop(); if(i&1) printf("%d ",-x.Fir); if(x.Sec.Sec<n) _heap.push(make_pair(-Kth(root,x.Sec.Sec+1,a[x.Sec.Fir],1<<30),make_pair(x.Sec.Fir,x.Sec.Sec+1))); } return 0; }
相关文章推荐
- 【bzoj3689】【异或之】【trie树+堆】
- 【BZOJ3689】异或之 堆+可持久化Trie树
- BZOJ[3689] 异或之 Trie树+堆
- bzoj 3261: 最大异或和 (可持久化trie树)
- BZOJ 3689: 异或之 字典树 优先队列
- 【bzoj 3261】最大异或和(可持久化Trie树)
- bzoj 3689: 异或之 Trie+堆
- BZOJ 3689 异或之
- 异或之(bzoj 3689)
- BZOJ 3689 异或之
- BZOJ 3689 异或 Trie木+堆
- 【BZOJ 4103】[Thu Summer Camp 2015]异或运算 可持久化trie树
- bzoj 3689: 异或之
- BZOJ 3689: 异或之
- BZOJ 3689 异或之 Trie树+堆
- BZOJ3689: 异或之
- BZOJ3689 异或之
- [乱搞 || 可持久化字典树 堆] BZOJ3689 异或之
- BZOJ 3689 异或之
- BZOJ 3689: 异或之