Xor-MST
Xor-MST
https://ac.nowcoder.com/acm/problem/112412
题意: 给定个点,每个点的权值为
,点
和点
之间的边的边权为
。求由这
个点构成的完全图的最小生成树的权值。
数据范围:
题解: 考虑分治法求解最小生成树的思想。那么可以将最小生成树的权值按照每一个二进制位进行分组,然后组内求解,再枚举比较两个组之间的数可以构成的最小权值即可,这里可以用树进行操作降低复杂度至
。
具体做法:从最高位开始分组,先处理组与组之间的合并大小,然后再处理各自组内的生成树权值即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int son[N * 32][2], idx = 1;
int n;
vector<int> tmp[N * 32];
ll ans = 0;
void insert(int x) {
int p = 1;
for(int i = 30; i >= 0; --i) {
int u = x >> i & 1;
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
tmp[p].push_back(x);
}
}
ll get(int p, int x, int dep) {
if(dep < 0) return 0ll;
int u = x >> dep & 1;
if(son[p][u]) return get(son[p][u], x, dep - 1);
return get(son[p][!u], x, dep - 1) + (1 << dep);
}
void solve(int p, int dep) {
int a = son[p][0], b = son[p][1];
if(a && b) {
ll mn = 1e18;
if(tmp[a].size() > tmp[b].size()) swap(a, b);
for(int i = 0; i < tmp[a].size(); ++i) mn = min(mn, get(b, tmp[a][i], dep - 1));
ans += mn + (1 << dep);
}
if(a) solve(a, dep - 1);
if(b) solve(b, dep - 1);
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
int x; scanf("%d", &x);
insert(x);
}
solve(1, 30);
printf("%lld\n", ans);
return 0;
} 
