cf888 G. Xor-MST Boruvka算法 + tire 树+贪心

 

很明显的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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值