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++中的“^”。
Solution
堆+Tire
如果在Tire上贪心就是求第1小(大)数啦
注意如果查询第一小数会查到他自己,所以k最好++
查询第2小就好啦~
因为查询k小,所以在每个tire的节点上维护一个size域,如果k<=当前位相同的size域的话,就往相同方向走,否则就往相反方向走,然后k减一下
首先把第一小都丢进堆里,如果pop出第k小的话就把k+1丢进去
- 为毛线我的左偏树常数那么大。。
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
int n, k;
int a[maxn];
struct Node{
int l, r, dis, val, pos, kth;
Node(int val = 0, int pos = 0, int kth = 0, int dis = 0, int l = 0, int r = 0):
val(val), pos(pos), kth(kth), dis(dis), l(l), r(r){}
bool operator<(const Node& k)const{return val < k.val;}
}TMP;
namespace Tire{
int t[3000000][2], size[3000000];
int root, Newnode;
void Insert(int p){
int now = root;
for(int i = 30; i >= 0; i --){
int q = p >> i & 1;
if(!t[now][q])t[now][q] = ++ Newnode;
now = t[now][q];
size[now] ++;
}
}
int Get_Kth(int p, int k){
k ++;int ret = 0, now = root;
for(int i = 30; i >= 0; i --){
int Q = p >> i & 1;
if(k <= size[t[now][Q]])
now = t[now][Q];
else{
k -= size[t[now][Q]];
ret |= 1 << i;
now = t[now][Q^1];
}
}return ret;
}
}
namespace Heap{
Node T[3000000];
int root, size;
int merge(int a, int b){
if(!a || !b)return a + b;
if(T[b] < T[a])swap(a, b);
T[a].r = merge(T[a].r, b);
if(T[T[a].l].dis < T[T[a].r].dis)
swap(T[a].l, T[a].r);
T[a].dis = T[a].r ? T[T[a].r].dis + 1 : 0;
return a;
}
void push(int val, int pos, int kth){
T[++ size] = Node(val, pos, kth);
root = merge(root, size);
}
void Get_pop(){
TMP = T[root];
root = merge(T[root].l, T[root].r);
}
}
int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++)
Tire::Insert(a[i]);
for(int i = 1; i <= n; i ++)
Heap::push(Tire::Get_Kth(a[i], 1), i, 1);
k <<= 1;
for(int i = 1; i <= k; i ++){
Heap::Get_pop();//get_TMP
if(i & 1)printf("%d ", TMP.val);
if(TMP.kth != n-1)
Heap::push(Tire::Get_Kth(a[TMP.pos], TMP.kth + 1), TMP.pos, TMP.kth + 1);
}
return 0;
}