Problem - G - Codeforces
\(n\) 个点,每个点都有一个 \(a_i\), 点 \(i\) 和 \(j\) 的边的权值等于 \(a_i\oplus a_j\),问最小生成树的权值(所有边权之和)。
代码
| C++ |
|---|
| #include <bits/stdc++.h>
using namespace std;
// 2023 OneWan
int tot = 0;
const int N = 200000 * 31;
vector<int> e[N];
int nxt[N][2];
void insert(int x) {
int index = 0;
for (int i = 30 ; i >= 0 ; i--) {
int k = x >> i & 1;
if (nxt[index][k] == 0) {
nxt[index][k] = ++tot;
}
index = nxt[index][k];
e[index].emplace_back(x);
}
}
int query(int index, int d, int x) {
if (d < 0) {
return 0;
}
int k = x >> d & 1;
if (nxt[index][k]) {
return query(nxt[index][k], d - 1, x);
}
return query(nxt[index][k ^ 1], d - 1, x) + (1 << d);
}
long long ans = 0;
void solve(int index, int d) {
int L = nxt[index][0], R = nxt[index][1];
if (L && R) {
if (e[L].size() > e[R].size()) swap(L, R);
int mi = 1 << 30;
for (auto &x : e[L]) {
mi = min(mi, query(R, d - 1, x));
}
ans += mi + (1 << d);
}
if (L) {
solve(L, d - 1);
}
if (R) {
solve(R, d - 1);
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1 ; i <= n ; i++) {
cin >> a[i];
insert(a[i]);
}
solve(0, 30);
cout << ans << "\n";
return 0;
}
|