Codeforces 888G Xor-MST - 分治 - 贪心 - Trie

题目传送门

  这是一条通往vjudge的高速公路

  这是一条通往Codeforces的高速公路

题目大意

  给定一个$n$阶完全图,每个点有一个权值$a_{i}$,边$(i, j)$的权值是$(a_{i}\  xor\  a_{j})$。一个生成树的权值是各边的权值和。问最小生成树的权值。  

  设值域为$[0, 2^{k})$。

  当$k = 1$的时候,显然将点权为0的点之间互相连边,点权为1的点之间互相连边,中间随便连一条。

  当$k = x\ (x > 1)$的时候,将这些点按照二进制的第$k$位分成两个集合。因为这两集合中间的点互相连边,边权的第$k$位会被消掉,于是变成了$k = x - 1$的子问题。

  假如得到了它们的最优解,那么我只需要在两个连通块之间添加一条边权最小的边就行了。

  考虑怎么找这样一条边。

  我可以把其中一个集合中数插入Trie树,然后拿另一集合中的点的点权在Trie树中查最小异或和。

Code

  1 /**
  2  * Codeforces
  3  * Problem#888G
  4  * Accepted
  5  * Time: 327ms
  6  * Memory: 49772k
  7  */
  8 #include <bits/stdc++.h>
  9 #ifndef WIN32
 10 #define Auto "%lld"
 11 #else
 12 #define Auto "%I64d"
 13 #endif
 14 using namespace std;
 15 typedef bool boolean;
 16 
 17 #define ll long long
 18 
 19 typedef class TrieNode {
 20     public:
 21         TrieNode* ch[2];
 22         
 23         TrieNode():ch({NULL, NULL}) {    }
 24 }TireNode;
 25 
 26 TrieNode pool[6000000];
 27 TrieNode* top = pool;
 28 
 29 TrieNode* newnode() {
 30     top->ch[0] = top->ch[1] = NULL;
 31     return top++;
 32 }
 33 
 34 typedef class Trie {
 35     public:
 36         TrieNode* rt;
 37         
 38         Trie() {
 39             top = pool;
 40             rt = newnode();
 41         }
 42         
 43         void insert(int x, int dep) {
 44             int temp = 1 << dep, d;
 45             TrieNode *p = rt;
 46             while (temp) {
 47                 d = (temp & x) ? (1) : (0);
 48                 if (!p->ch[d])
 49                     p->ch[d] = newnode();
 50                 p = p->ch[d], temp = temp >> 1;
 51             }
 52         }
 53         
 54         int query(int x, int dep) {
 55             int temp = 1 << dep, rt = 0, d;
 56             TrieNode *p = this->rt;
 57             while (temp) {
 58                 d = (temp & x) ? (1) : (0);
 59                 if (p->ch[d])
 60                     p = p->ch[d];
 61                 else
 62                     p = p->ch[d ^ 1], rt |= temp;
 63                 temp = temp >> 1;
 64             }
 65             return rt;
 66         }
 67 }Trie;
 68 
 69 int n;
 70 int *ar;
 71 Trie t;
 72 
 73 inline void init() {
 74     scanf("%d", &n);
 75     ar = new int[(n + 1)];
 76     for (int i = 1; i <= n; i++)
 77         scanf("%d", ar + i);
 78 }
 79 
 80 ll dividing(int dep, int l, int r) {
 81     if (!dep)    return ar[l] ^ ar[r];
 82     int tl = l, tr = r, mid, temp = 1 << dep, mincost = 1 << 30;
 83     while (tl <= tr) {
 84         mid = (tl + tr) >> 1;
 85         if (ar[mid] & temp)
 86             tr = mid - 1;
 87         else
 88             tl = mid + 1;
 89     } 
 90     if (tr == l - 1 || tr == r)
 91         return dividing(dep - 1, l, r);
 92     t = Trie();
 93     for (int i = l; i <= tr; i++)
 94         t.insert(ar[i], dep);
 95     for (int i = tr + 1; i <= r; i++)
 96         mincost = min(mincost, t.query(ar[i], dep));
 97     return mincost + dividing(dep - 1, l, tr) + dividing(dep - 1, tr + 1, r);
 98 }
 99 
100 inline void solve() {
101     sort(ar + 1, ar + n + 1);
102     printf(Auto"\n", dividing(29, 1, n));
103 }
104 
105 int main() {
106     init();
107     solve();
108     return 0;
109 }
posted @ 2018-03-04 16:14  阿波罗2003  阅读(290)  评论(0编辑  收藏  举报