1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| #include <bits/stdc++.h>
using namespace std;
const int MAXN = 2E5 + 5; int n, m, a[MAXN], fa[MAXN], root[MAXN], minEdge[MAXN], nxt[MAXN];
template <class T> void read(T& x, T f = 1, char ch = getchar()) { x = 0; while (ch < '0' || ch > '9') f = (ch == '-' ? -1 : 1), ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - 48, ch = getchar(); x *= f; }
struct Trie { int son[2], sz, id; Trie() { son[0] = son[1] = sz = id = 0; } } tr[MAXN * 31 * 2];
void insert(int root, int id) { static int cntNode = n + 1; int cur = root; for (int i = 30; ~i; i--) { int to = (a[id] >> i) & 1; if (!tr[cur].son[to]) tr[cur].son[to] = ++cntNode; cur = tr[cur].son[to]; tr[cur].sz++; } tr[cur].id = id; }
int merge(int root1, int root2) { if (!root1 || !root2) return root1 + root2; tr[root1].sz += tr[root2].sz; for (int i = 0; i < 2; i++) tr[root1].son[i] = merge(tr[root1].son[i], tr[root2].son[i]); return root1; }
int query(int root1, int root2, int val) { for (int i = 30; ~i; i--) { int to = (val >> i) & 1; if (tr[tr[root1].son[to]].sz > tr[tr[root2].son[to]].sz) root1 = tr[root1].son[to], root2 = tr[root2].son[to]; else root1 = tr[root1].son[to ^ 1], root2 = tr[root2].son[to ^ 1]; } return tr[root1].id; }
int find(int x) { if (fa[x] != x) fa[x] = find(fa[x]); return fa[x]; }
void Boruvka() { long long sum = 0; for (int i = 1; i <= n; i++) fa[i] = i, insert(root[i], i); bool tag = true; while (tag) { tag = false; fill(minEdge + 1, minEdge + n + 1, -1); for (int i = 1; i <= n; i++) { int r1 = find(i); int id = query(root[0], root[r1], a[i]); if (!id) continue; int len = a[id] ^ a[i]; int r2 = find(id); if (minEdge[r1] == -1 || len < minEdge[r1]) minEdge[r1] = len, nxt[r1] = r2; if (minEdge[r2] == -1 || len < minEdge[r2]) minEdge[r2] = len, nxt[r2] = r1; } for (int i = 1; i <= n; i++) { if (minEdge[i] != -1 && find(i) != find(nxt[i])) { tag = true; merge(root[find(i)], root[find(nxt[i])]); sum += minEdge[i]; fa[find(nxt[i])] = i; } } } cout << sum; }
int main() { read(n); for (int i = 1; i <= n; i++) read(a[i]); sort(a + 1, a + n + 1); for (int i = 0; i <= n; i++) root[i] = i + 1; for (int i = 1; i <= n; i++) insert(root[0], i); Boruvka(); return 0; }
|