CF437D The Child and Zoo

题意:

题面

分析:

一句话题意:求任意两点之间各条简单路径上最小值的最大值的平均数(我好像也没说人话

这题的 n n n 极大,所以我们没有办法优化正常的暴力,所以我们考虑将式子拆开来计算,我们考虑每一个点在什么情况下会被选,那肯定在当它是一对点各条简单路径上最小值的最大值的时候,我们发现各条简单路径的最小值这个条件过于恶心,那么思考怎么消掉这个条件

我们只需要将任意两点通过它们路径上点权的最小值连接起来就可以了,由于点权无法连接两个点,那么我们将点权压到边权上去, w ( u → v ) = m i n ( v a l [ u ] , v a l [ v ] ) w(u \to v)=min(val[u],val[v]) w(uv)=min(val[u],val[v]) ,然后我们求一个最小瓶颈生成树就可以了,那么在树上我们就可以 n 2 n^2 n2 的统计任意两点间路径最小值的平均数了,但这还是不行,那就继续考虑拆式子,考虑一条边会在什么时候向答案做出贡献,那就是在它是现在情况下最小的边时,我们发现这样每个边的贡献就是在模拟最小瓶颈生成树的生成过程,每条边会被连接的两个连通块统计上一次,直接上并查集就可以了

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
	const int maxn = 2e5+5;
	int n,m,cnt,tot;
	int head[maxn],fa[maxn],siz[maxn];
	double v[maxn],ans;
	
	struct edge
	{
		int frm,to;
		double val;
	}e[maxn];
	
	bool cmp(edge a,edge b)
	{
		return a.val>b.val;
	}
	
	int find(int x)
	{
		return fa[x]==x?x:fa[x]=find(fa[x]);
	}
	
	void merge(int x,int y)
	{
		int fx=find(x);
		int fy=find(y);
		if(fx!=fy)
		{
			if(siz[fx]<siz[fy]) swap(fx,fy);
			siz[fx]+=siz[fy];
			fa[fy]=fx;
		}
	}
	
	void work()
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) scanf("%lf",&v[i]),fa[i]=i,siz[i]=1;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&e[i].frm,&e[i].to);
			e[i].val=min(v[e[i].frm],v[e[i].to]);
		}
		sort(e+1,e+m+1,cmp);
		for(int i=1;i<=m&&tot<n;i++)
		{
			int u=find(e[i].frm);
			int v=find(e[i].to);
			double w=e[i].val;
			if(u!=v)
			{
				tot++;
				ans+=w*siz[u]*siz[v];
				merge(u,v);
			}
		}
		printf("%.6f\n",ans/n*2/(n-1));
	}

}

int main()
{
	zzc::work();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值