BZOJ 3689: 异或之

 

字典树可以$o(logn)查找第k大$

使用$可持久化Trie 区间查找第k大,然后首先把每个数异或之后的最小丢进小根堆中,然后一个一个取出,取出后就再丢次小,一共取k次$

总的时间复杂度为$O(klogn)$

 

本来的考虑是 先找出第k大,然后在$Trie上DFS把小于这个数的全丢进vector  然后发现会有很多无用状态会搜索到,T掉$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 int n, k, arr[N], kth;
 6 struct node
 7 {
 8     int base, num, pos, l, r;
 9     node () {}
10     node (int base, int num, int pos, int l, int r) : base(base), num(num), pos(pos), l(l), r(r) {}
11     bool operator < (const node &r) const { return num > r.num; }
12 };
13 priority_queue <node> q;  
14 
15 namespace TRIE
16 {
17     int rt[N], cnt; 
18     struct node
19     {
20         int son[2], cnt;
21     }a[N * 50];  
22     void init()
23     {
24         a[1].son[0] = a[1].son[1] = a[1].cnt = 0; 
25         cnt = 0; 
26     }  
27     void insert(int &now, int pre, int x)  
28     {
29         now = ++cnt;
30         a[now] = a[pre];
31         int root = now; ++a[root].cnt; 
32         for (int i = 30; i >= 0; --i)
33         {
34             int id = (x >> i) & 1; 
35             a[++cnt] = a[a[root].son[id]]; 
36             ++a[cnt].cnt;
37             a[root].son[id] = cnt;
38             root = cnt;  
39         }
40     } 
41     int find_kth(int x, int k, int l, int r)
42     {
43         int res = 0;
44         int tl = rt[l], tr = rt[r];
45         for (int s = 30; s >= 0; --s)
46         {
47             int id = (x >> s) & 1;
48             int sum = a[a[tr].son[id]].cnt - a[a[tl].son[id]].cnt;
49             if (sum < k)
50             {
51                 k -= sum;
52                 res |= 1 << s;
53                 tr = a[tr].son[id ^ 1];
54                 tl = a[tl].son[id ^ 1];
55             }    
56             else
57             {
58                 tr = a[tr].son[id];
59                 tl = a[tl].son[id]; 
60             }
61         }
62         return res;
63     }
64 }
65 
66 int main()
67 {
68     while (scanf("%d%d", &n, &k) != EOF) 
69     {
70         for (int i = 1; i <= n; ++i) scanf("%d", arr + i);
71         TRIE::init(); 
72         for (int i = 1; i <= n; ++i) TRIE::insert(TRIE::rt[i], TRIE::rt[i - 1], arr[i]);
73         for (int i = 1; i < n; ++i) q.push(node(arr[i], TRIE::find_kth(arr[i], 1, i, n), 2, i, n)); 
74         for (int i = 1; i <= k; ++i)
75         {
76             node top = q.top(); q.pop();
77             printf("%d%c", top.num, " \n"[i == k]);
78             q.push(node(top.base, TRIE::find_kth(top.base, top.pos, top.l, top.r), top.pos + 1, top.l, top.r));
79         }    
80     }
81     return 0;
82 }
View Code

 

posted @ 2018-11-23 21:09  Dup4  阅读(176)  评论(0编辑  收藏  举报