• UOJ176 新年的繁荣


    题意

    有一张(n)个点的完全图,点权为(a[i])(w_{i,j}=a_i mathbin{mathrm{and}} a_j)。问这个图的最大生成树。
    (n leq 10^5,a[i]<2^{18})

    思路

    本来想写个(Boruvka),然后发现可以用熟知的(Kruskal)过掉。
    因为边权很小,所以可以枚举边权,考虑这条边有没有贡献。
    可以考虑如果两个点点权相同,那么它们连起来,一定是最优的。这样我们就可以直接加上相同点的贡献,然后留下互不相同的点,以他们的点权为编号。
    对于(i)的边权,我们可以枚举所有(x & y=i),如果存在(x,y)(father[x] eq father[y])那么就贪心连起来。但是枚举(x,y)实在是做不到,因此我们可以将(x)传递到(x)的子集中,这样子就只需枚举(i|2^j)了。

    #include <bits/stdc++.h>
    const int N=100005;
    int a[1<<20],f[1<<20],n,m,x;
    long long ans;
    int find(int x){
    	if (f[x]==x) return x;
    	f[x]=find(f[x]);
    	return f[x];
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++){
    		scanf("%d",&x);
    		if (a[x]) ans+=x;
    		a[x]=x;
    	}
    	for (int i=1;i<1<<m;i++) f[i]=i;
    	for (int i=(1<<m)-1;i>=1;i--){
    		for (int j=0;j<m && !a[i];j++)
    			a[i]=a[i|(1<<j)];
    		int fx=find(a[i]);
    		for (int j=0;j<m;j++){
    			if (!a[i|(1<<j)]) continue;
    			int fy=find(a[i|(1<<j)]);
    			if (fx==fy) continue;
    			ans=ans+i;
    			fx=f[fx]=fy;
    		} 
    	}
    	printf("%lld
    ",ans);
    } 
    

    后记

    被吐槽好久没更了,所以来写一篇不是那么清楚的

  • 相关阅读:
    1、SpringBoot入门
    在一台电脑开启多个微信
    【监控】prometheus监控安装
    【hadoop3.0】hive 安装
    【google工具安装】gsutil存储管理google cloud stroge
    [监控报警]elastalert安装使用
    【大数据】hadoop3.0worker集群+flink+zeppelin+kafaka+zookeeper安装部署
    【原创】fluent-bit安装使用
    [etcd]etcd集群部署
    【手打】kafka集群设置
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11993206.html
Copyright © 2020-2023  润新知