[BZOJ 3689]異或之

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章