[Trie树] BZOJ3689: 异或之

题意

给定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小的数。
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;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值