[BZOJ 3689]异或之

来源:互联网 发布:js获取当前页面url 编辑:程序博客网 时间:2024/04/28 06:28

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 100010using 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;}
0 0
原创粉丝点击