UOJ176 新年的繁荣
Posted flyfeather6
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
}
后记
被吐槽好久没更了,所以来写一篇不是那么清楚的
以上是关于UOJ176 新年的繁荣的主要内容,如果未能解决你的问题,请参考以下文章