• 【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;
    }
  • 相关阅读:
    洗礼灵魂,修炼python(48)--巩固篇—模块
    洗礼灵魂,修炼python(48)--巩固篇—模块
    洗礼灵魂,修炼python(48)--巩固篇—模块
    Excel中拆分列
    Excel中拆分列
    Excel中拆分列
    Excel中拆分列
    Eclipse新建类的时候如何自动添加注释(作者,时间,版本等信息)
    Eclipse新建类的时候如何自动添加注释(作者,时间,版本等信息)
    用golang实现DDOS攻击网站
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8052013.html
Copyright © 2020-2023  润新知