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 }