Xor-MST
题目描述
照例贴传送门http://codeforces.com/problemset/problem/888/G
题解
异或最小生成树。
分治的思想,按位从大到小贪心。
每位把0的和1的分开,两组分别在内部连边,并在中间加一条边。
可以证明这样最优。
对于两组中间连边的权值,考虑一样的思想,从大到小一位一位贪心。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 2100000000
#define N 200005
using namespace std;
int n,s[N];
ll cal(int d,int l1,int r1,int num1,int l2,int r2,int num2)
{
if(d<0)return 0;
int p1,p2,aa=num1+(1<<d),bb=num2+(1<<d);ll A=inf,B=inf;
if(s[r1]<aa&&s[l2]>=bb)
return cal(d-1,l1,r1,num1,l2,r2,num2+(1<<d))+(1<<d);
if(s[l1]>=aa&&s[r2]<bb)
return cal(d-1,l1,r1,num1+(1<<d),l2,r2,num2)+(1<<d);
p1=lower_bound(s+l1,s+r1+1,aa)-s-1;
p2=lower_bound(s+l2,s+r2+1,bb)-s-1;
if(s[l1]<aa&&s[l2]<bb)A=cal(d-1,l1,p1,num1,l2,p2,num2);
if(s[r1]>=aa&&s[r2]>=bb)
B=cal(d-1,p1+1,r1,num1+(1<<d),p2+1,r2,num2+(1<<d));
return min(A,B);
}
ll solve(int num,int d,int l,int r)
{
if(d<0||l==r)return 0;
if(s[r]<num+(1<<d))return solve(num,d-1,l,r);
if(s[l]>=num+(1<<d))return solve(num+(1<<d),d-1,l,r);
int mid=lower_bound(s+l,s+r+1,num+(1<<d))-s-1;
ll A=solve(num,d-1,l,mid);
ll B=solve(num+(1<<d),d-1,mid+1,r);
ll C=cal(d,l,mid,num,mid+1,r,num);
return A+B+C;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&s[i]);
sort(s+1,s+n+1);
printf("%I64d\n",solve(0,30,1,n));
return 0;
}