【CF888G】Xor-MST Trie树(模拟最小生成树)

【CF888G】Xor-MST

题意:给你一张n个点的完全图,每个点有一个权值ai,i到j的边权使ai^aj,求这张图的最小生成树。

n<=200000,ai<2^30

题解:学到了求最小生成树的新姿势。

Boruvka算法:先对于每个点,选择在所有与之相连的边中,权值最小的边,并将这条边加入到最小生成树中。显然这样连出来的边会形成一个森林,并且连边后连通块个数至少减半。然后我们将每个连通块再看成一个点,重复以上算法即可。时间复杂度O(mlogn)。

对于本题,该如何优化呢?不难想到Trie树。我们很容易就能找到对于一个点,它与所有其它连通块中的点的连边中,权值最小的是哪个。然后这题就做完了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=200010;
ll ans;
int n,m,tot;
int to[maxn],val[maxn],rt[maxn],f[maxn],v[maxn],bel[maxn];
vector<int> p[2][maxn];
vector<int>::iterator it;
struct node
{
	int ch[2],siz;
}s[maxn*61];
inline void insert(int &x,int z,int w)
{
	if(!x)	x=++tot;
	int i,u=x,d;
	for(i=29;~i;i--)
	{
		d=(w>>i)&1;
		if(!s[u].ch[d])	s[u].ch[d]=++tot;
		u=s[u].ch[d],s[u].siz++;
	}
	s[u].siz=z;
}
inline void query(int x,int y,int z,int w)
{
	int i,d,ret=0;
	for(i=29;~i;i--)
	{
		d=(w>>i)&1;
		if(s[s[x].ch[d]].siz==s[s[y].ch[d]].siz)	d^=1,ret|=(1<<i);
		x=s[x].ch[d],y=s[y].ch[d];
	}
	if(ret<val[z])	val[z]=ret,to[z]=s[x].siz;
}
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,d=0;
	for(i=1;i<=n;i++)	v[i]=rd();
	sort(v+1,v+n+1);
	for(i=1;i<=n;i++)	if(i==1||v[i]>v[i-1])	p[0][++m].push_back(v[i]);
	while(m>1)
	{
		n=m,m=0,memset(val,0x3f,sizeof(val[0])*(n+1)),memset(rt,0,sizeof(rt[0])*(n+1));
		memset(s,0,sizeof(s[0])*(tot+1)),tot=0;
		for(i=1;i<=n;i++)	for(it=p[d][i].begin();it!=p[d][i].end();it++)	insert(rt[i],i,*it),insert(rt[0],i,*it);
		for(i=1;i<=n;i++)	for(it=p[d][i].begin();it!=p[d][i].end();it++)	query(rt[0],rt[i],i,*it);
		for(i=1;i<=n;i++)	p[d^1][i].clear(),f[i]=i;
		for(i=1;i<=n;i++)	if(find(to[i])!=find(i))	f[f[i]]=f[to[i]],ans+=val[i];
		for(i=1;i<=n;i++)	if(find(i)==i)	bel[i]=++m;
		for(i=1;i<=n;i++)	for(it=p[d][i].begin();it!=p[d][i].end();it++)	p[d^1][bel[f[i]]].push_back(*it);
		d^=1;
	}
	printf("%I64d",ans);
	return 0;
}
posted @ 2017-12-17 14:23  CQzhangyu  阅读(691)  评论(0编辑  收藏  举报