很明显的Boruvka题。
现在目的就是快速找到某个联通块连出的权值最小的边。。显然 用字典树不可做。。
我们仔细观察条件,按位异或,自然的想到从高位开始。
把最高位为0的和为1的分成2组,这两组之间连一条权值最小的边,其他内部连,一定是最优解。。(根据Boruvka的思想)
其实不需要知道Boruvka算法,只需要知道这样是对的就行。。证明显然。。
然后分成两个联通块,分治下去搞搞就行。。
最多29层,每层On 复杂度合理
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e5+7;
int a[M];
int ti[M*32][2],cnt;//字典树
ll ans;
void in(int x)
{
int k=0;
for(int i=29;i>=0;i--)
{
int id=(x>>i)&1;
if(ti[k][id]==0)
{
ti[k][id]=++cnt;
k=cnt;ti[k][0]=ti[k][1]=0;
}
else k=ti[k][id];
}
}
int fd(int x)//找到字典树中存的树与x异或最小
{
int k=0,ans=0;
for(int i=29;i>=0;i--)
{
int id=(x>>i)&1;
if(ti[k][id]==0)id^=1;
k=ti[k][id];
if(id)ans|=(1<<i);
}
return ans;
}
void dfs(int id,int l,int r)
{
if(id<0)return ;
int mid=l-1;
for(int i=l;i<=r;i++)
if(((a[i]>>id)&1)==0)
mid=i;
if(l<=mid)dfs(id-1,l,mid);
if(mid+1<=r)dfs(id-1,mid+1,r);
if(l<=mid&&mid+1<=r)//这一步放在dfs前和dfs后都行
{
cnt=0;
ti[0][0]=ti[0][1]=0;
for(int i=l;i<=mid;i++)in(a[i]);
int mi=2e9;
for(int i=mid+1;i<=r;i++)
mi=min(mi,a[i]^fd(a[i]));
ans+=mi;
}
// cout<<id<<" "<<l<<" "<<r<<" "<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
dfs(29,1,n);
cout<<ans<<endl;
return 0;
}