• CF888G Xor-MST


    cf

    luogu

    这题(prim)(kruskal)似乎都不可做,考虑(Boruvka)算法,维护一堆连通块,对于每个连通块每次找出其他连通块和它的最小权值的边,然后只用这些边合并连通块,首先这样子做是对的,因为参考(prim),连通块应该用最小权的边和其他连通块合并,并且每次合并连通块数量至少少一半,所以只要做(logn)次.至于找其他连通块到它的最小权值的边,可以考虑(trie),每次把自己联连通块内的点在(trie)上的点删掉,然后枚举连通块内每个点查询与其他点的异或最小值

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=2e5+10;
    int rd()
    {
    	int x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    int n,a[N],ff[N],stk[N][3],tp;
    int findf(int x){return ff[x]==x?x:ff[x]=findf(ff[x]);}
    int q[N],hd,tl,op[N*30],tot;
    int s[N*30],ch[N*30][2],id[N*30],rt,tt;
    vector<int> e[N];
    vector<int>::iterator it;
    LL ans;
    
    int main()
    {
    	n=rd();
    	rt=++tt;
    	int rs=n-1;
    	for(int i=1;i<=n;++i) a[i]=rd();
    	sort(a+1,a+n+1);
    	for(int i=1;i<=n;++i)
    	{
    		ff[i]=i;
    		int o=rt;
    		++s[o];
    		for(int j=29;~j;--j)
    		{
    			int xx=a[i]>>j&1;
    			if(!ch[o][xx]) ch[o][xx]=++tt;
    			o=ch[o][xx];
    			++s[o];
    		}
    		if(id[o]) ff[id[o]]=i,e[i].push_back(id[o]),--rs; 
    		id[o]=i;
    	}
    	while(rs)
    	{
    		for(int i=1;i<=n;++i)
    			if(findf(i)==i)
    			{
    				hd=1,q[tl=1]=i;
    				while(hd<=tl)
    				{
    					int x=q[hd++],o=1;
    					op[++tot]=o;
    					--s[o];
    					for(int j=29;~j;--j)
    					{
    						int xx=a[x]>>j&1;
    						o=ch[o][xx];
    						--s[o];
    						op[++tot]=o;
    					}
    					for(it=e[x].begin();it!=e[x].end();++it)
    						q[++tl]=*it;
    				}
    				int zz=0,mi=1<<30;
    				hd=1,q[tl=1]=i;
    				while(hd<=tl)
    				{
    					int x=q[hd++],o=1;
    					for(int j=29;~j;--j)
    					{
    						int xx=a[x]>>j&1;
    						if(s[ch[o][xx]]) o=ch[o][xx];
    						else o=ch[o][xx^1];
    					}
    					if(mi>(a[x]^a[id[o]])) mi=a[x]^a[id[o]],zz=id[o];
    					for(it=e[x].begin();it!=e[x].end();++it)
    						q[++tl]=*it;
    				}
    				stk[++tp][0]=i,stk[tp][1]=findf(zz),stk[tp][2]=mi;
    				while(tot) ++s[op[tot]],--tot;
    			}
    		while(tp)
    		{
    			int x=findf(stk[tp][0]),y=findf(stk[tp][1]),z=stk[tp][2];
    			if(x!=y)
    			{
    				ans+=z;
    				ff[y]=x;
    				e[x].push_back(y);
    				--rs;
    			}
    			--tp;
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    powershel学习(1)
    JS作用域链(转载)
    C# 对QuotedPrintable进行解码的方法
    SortedList、SortedSet、HashSet、Hashtable、Dictionary、SortedDictionary 排序/可重复排序/过滤重复排序等简单对比
    .net windows 服务中返回服务的安装目录
    c# 中图像的简单二值化处理
    windows下开多个CMD窗口多个进程输出
    生命游戏
    PowerDesigner工具简介
    七大面向对象设计原则(转)
  • 原文地址:https://www.cnblogs.com/smyjr/p/11623565.html
Copyright © 2020-2023  润新知