【bzoj3689】【异或之】【trie树+堆】

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

题解:对所有的数建立trie树.

            每个节点多记一个size,表明这个点下面有多少单词.这样就可以查第k小的异或值了。

            首先把每个数的第二小的异或之压进堆中。因为第一小一定是和它自己。

            由于一个异或值会被两个数各记录一遍,

            所以我们取k*2次堆顶,只在奇数次取堆顶的时候输出答案。

            假设取出了一个数的第k小异或值,那就把它的第k+1小异或值入堆即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue> 
#define N 100010 
using namespace std;
int n,a[N],k,mx;
struct use{
  int k,v,a;
};
bool operator<(use x,use y){return x.v>y.v;}
priority_queue<use>q;
struct abc{
 int cnt,ch[N*30][3],size[N*30];
 void insert(int x){
   int now(0);
   for (int i=30;i>=0;i--){
     int t=x&(1<<i);t>>=i;
     if (!ch[now][t]) ch[now][t]=++cnt;
     now=ch[now][t];size[now]++;  
   }
 }
 int query(int x,int k){
   int now(0),temp(0);
   for (int i=30;i>=0;i--){
     int t=x&(1<<i);t>>=i;
     if (size[ch[now][t]]>=k) now=ch[now][t];
     else k-=size[ch[now][t]],now=ch[now][t^1],temp+=(1<<i); 
   }
  return temp;
 }  
}trie;
int main(){ 
  scanf("%d%d",&n,&k);
  for (int i=1;i<=n;i++)
   scanf("%d",&a[i]),trie.insert(a[i]);
  for (int i=1;i<=n;i++){
     use t;
     t.v=trie.query(a[i],2);t.k=2;t.a=a[i];
     q.push(t);
  }
  for (int i=1;i<=k<<1;i++){  
    use t=q.top();q.pop();  
    if (i&1) printf("%d ",t.v);
    if (t.k==n) continue;t.k++;  
    t.v=trie.query(t.a,t.k);  
    q.push(t);  
    } 
} 

    原文作者:Trie树
    原文地址: https://blog.csdn.net/sunshinezff/article/details/51056494
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞