P8905 [USACO22DEC] Strongest Friendship Group G 题解

该文讨论了一个关于图的问题,寻找具有最大团体人数同时保证团体内最小度的算法。通过枚举最小度并动态删除节点,使用并查集维护连通块大小,最终找到最大团体的解。

决定小团体强度的值有两个:

  • 团体内的最小度。
  • 团体人数。

我们可以考虑枚举最小度求最大的团体人数。

我们发现小于原图最小度的度肯定不优,因为原图最小度可以直接选择包含全图使团体人数最大,这给了我们一个启发。

在之后,由于我们要增大团体内的最小度,所以最小度的点不会被包含,因此可以考虑删掉这些点。

这个时候问题由变回了原样,我们可以继续找最小度的点,如此类推。

注意到动态删点加维护连通块大小不好做,但是动态维护点的度数不难,我们先利用 set 维护删点顺序,再倒着加点,变成动态加点维护连通块大小,并查集即可维护。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=3e5+5;
LL n,m,x,y,ans,fa[N],a[N],du[N],d[N],sz[N],vis[N];
vector<LL>v[N];
stack<LL>s;
set<pair<LL,LL>>p;
LL find(LL x)
{
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)fa[i]=i,a[i]=i,sz[i]=1;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld",&x,&y);
		v[x].push_back(y);
		v[y].push_back(x);
		du[x]++,du[y]++;	
	}
	for(int i=1;i<=n;i++)
	{
		p.insert({du[i],i});
	}
	while(!p.empty())
	{
		LL t=(*p.begin()).second;
		p.erase(p.begin());
		s.push(t);
		d[t]=du[t];
		for(LL i:v[t])
		{
			if(d[i])continue;
			p.erase(p.lower_bound({du[i],i}));
			du[i]--;
			p.insert({du[i],i});
		}
	}
	for(int i=1;i<=n;i++)
	{
		LL t=s.top();
		vis[t]=1;
		s.pop();
		for(LL j:v[t])
		{
			if(vis[j]==0)continue;
			LL fx=find(t),fy=find(j);
			if(fx!=fy)
			{
				fa[fx]=fy;
				sz[fy]+=sz[fx];
			}
		}
		ans=max(ans,sz[find(t)]*d[t]);
	}
	printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值