zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    C89和C99区别--简单总结
    C语言 值传递和地址传递
    对于.h文件和.c文件
    C语言-------多文件编译
    数据结构之第二章线性表
    数据结构之第一章一些概念
    JS-prototype的掌握
    JS-return的使用
    分分钟搞懂JS-闭包函数
    JS-面向对象-封装
  • 原文地址:https://www.cnblogs.com/smyjr/p/11623565.html
Copyright © 2011-2022 走看看