/*
对于n个点的完全图,每两个点之间的距离等于两点的权值的异或和,求最小生成树
*/
int n;
struct XorTrie{
int dfn = 0;
int t[maxn*30][2];
int L[maxn*30],R[maxn*30],val[maxn*30],a[maxn];
void solve(){
sort(a+1, a+n+1);
for(int i = 1; i <= n; i++) Insert(a[i],i);
printf("%lld\n", Divide(0,32));
}
void Insert(ll x,int id){
int rt = 0;
for(int k=32;k>=0;k--){
int op = (x>>k&1ll)?1:0;
if(!t[rt][op]) t[rt][op] = ++dfn;
rt = t[rt][op];
if(!L[rt]) L[rt] = id;
R[rt] = id;
}
val[rt] = x;
}
ll AnswerPos(int rt,int pos,ll x){
for(int i=pos;i>=0;i--){
int op = (x>>i&1ll)?1:0;
if(t[rt][op]) rt = t[rt][op];
else rt = t[rt][!op];
}return rt;
}
void Traceback(int rt){
printf("%d %d\n",L[rt],R[rt]);
if(t[rt][0]) Traceback(t[rt][0]);
if(t[rt][1]) Traceback(t[rt][1]);
}
ll Divide(int rt,int pos){
if(t[rt][0]&&t[rt][1]){
int x = t[rt][0],y = t[rt][1];
ll minl = INF;
for(int k=L[y];k<=R[y];k++){
minl = min(minl,(ll)a[k]^val[AnswerPos(x,pos-1,a[k])]);
}
return minl+Divide(t[rt][0],pos-1)+Divide(t[rt][1],pos-1);
}
else if(t[rt][0]) return Divide(t[rt][0],pos-1);
else if(t[rt][1]) return Divide(t[rt][1],pos-1);
return 0;
}
}trie;
例题有codeforces888G,和牛客多校第五场B Graph
888G
B Graph
代码如下:
888G:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define IOS std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fopen freopen("file.in","r",stdin);freopen("file.out","w",stdout);
#define fclose fclose(stdin);fclose(stdout);
#define PI 3.14159265358979323846
const int inf = 1e9;
const ll INF = 1e18;
const int maxn = 2e5+10;
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
int n;
/*
*/
struct XorTrie{
int dfn = 0;
int t[maxn*30][2];
int L[maxn*30],R[maxn*30],val[maxn*30],a[maxn];
void solve(){
sort(a+1, a+n+1);
for(int i = 1; i <= n; i++) Insert(a[i],i);
printf("%lld\n", Divide(0,32));
}
void Insert(ll x,int id){
int rt = 0;
for(int k=32;k>=0;k--){
int op = (x>>k&1ll)?1:0;
if(!t[rt][op]) t[rt][op] = ++dfn;
rt = t[rt][op];
if(!L[rt]) L[rt] = id;
R[rt] = id;
}
val[rt] = x;
}
ll AnswerPos(int rt,int pos,ll x){
for(int i=pos;i>=0;i--){
int op = (x>>i&1ll)?1:0;
if(t[rt][op]) rt = t[rt][op];
else rt = t[rt][!op];
}return rt;
}
void Traceback(int rt){
printf("%d %d\n",L[rt],R[rt]);
if(t[rt][0]) Traceback(t[rt][0]);
if(t[rt][1]) Traceback(t[rt][1]);
}
ll Divide(int rt,int pos){
if(t[rt][0]&&t[rt][1]){
int x = t[rt][0],y = t[rt][1];
ll minl = INF;
for(int k=L[y];k<=R[y];k++){
minl = min(minl,(ll)a[k]^val[AnswerPos(x,pos-1,a[k])]);
}
return minl+Divide(t[rt][0],pos-1)+Divide(t[rt][1],pos-1);
}
else if(t[rt][0]) return Divide(t[rt][0],pos-1);
else if(t[rt][1]) return Divide(t[rt][1],pos-1);
return 0;
}
}tire;
signed main(){
n=read();
for(int i = 1; i <= n; i++){
tire.a[i]=read();
}
tire.solve();
return 0;
}
B-Graph
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define IOS std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fopen freopen("file.in","r",stdin);freopen("file.out","w",stdout);
#define fclose fclose(stdin);fclose(stdout);
#define PI 3.14159265358979323846
const int inf = 1e9;
const ll INF = 1e18;
const int maxn = 2e5+10;
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
/*
对于n个点的完全图,每两个点之间的距离等于两点的权值的异或和,求最小生成树
*/
int n;
struct XorTrie{
int dfn = 0;
int t[maxn*30][2];
int L[maxn*30],R[maxn*30],val[maxn*30],a[maxn];
void solve(){
sort(a+1, a+n+1);
for(int i = 1; i <= n; i++) Insert(a[i],i);
printf("%lld\n", Divide(0,32));
}
void Insert(ll x,int id){
int rt = 0;
for(int k=32;k>=0;k--){
int op = (x>>k&1ll)?1:0;
if(!t[rt][op]) t[rt][op] = ++dfn;
rt = t[rt][op];
if(!L[rt]) L[rt] = id;
R[rt] = id;
}
val[rt] = x;
}
ll AnswerPos(int rt,int pos,ll x){
for(int i=pos;i>=0;i--){
int op = (x>>i&1ll)?1:0;
if(t[rt][op]) rt = t[rt][op];
else rt = t[rt][!op];
}return rt;
}
void Traceback(int rt){
printf("%d %d\n",L[rt],R[rt]);
if(t[rt][0]) Traceback(t[rt][0]);
if(t[rt][1]) Traceback(t[rt][1]);
}
ll Divide(int rt,int pos){
if(t[rt][0]&&t[rt][1]){
int x = t[rt][0],y = t[rt][1];
ll minl = INF;
for(int k=L[y];k<=R[y];k++){
minl = min(minl,(ll)a[k]^val[AnswerPos(x,pos-1,a[k])]);
}
return minl+Divide(t[rt][0],pos-1)+Divide(t[rt][1],pos-1);
}
else if(t[rt][0]) return Divide(t[rt][0],pos-1);
else if(t[rt][1]) return Divide(t[rt][1],pos-1);
return 0;
}
}trie;
std::vector<pii> v[maxn];
void dfs(int rt, int pre){
for(auto i : v[rt]){
if(i.first==pre) continue;
trie.a[i.first] = trie.a[rt]^i.second;
dfs(i.first, rt);
}
}
signed main(){
n=read();
for(int i = 1; i < n; i++){
int x=read(), y=read(), z=read();
x++,y++;
v[x].push_back({y,z}), v[y].push_back({x,z});
}
dfs(1,0);
trie.solve();
return 0;
}