洛谷[USACO22DEC] Strongest Friendship Group G
题目大意
有一个 n n n个点 m m m条边的无向图,图中连通块的强度为该连通块中度数最小的点的度数和连通块的点的个数的乘积,求图中连通块的最大强度。
2 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 2\leq n\leq 10^5,1\leq m\leq 2\times 10^5 2≤n≤105,1≤m≤2×105
题解
假设这个无向图是连通的,那么选整个图当这个连通块的话,连通块的点的个数是最多的,但度数最小的点的度数是最小的。如果有强度更大的连通块,那么一定是这个图删去一些点得到的。既然删去了点,那么连通块的点的个数减少了,为保证强度更大,度数最小的点的度数要更大才行。也就是说,若当前连通块中度数最小的点的度数为 k k k,我们每次求一个新的连通块,需要将当前连通块中度数小于等于 k k k的点都删去(在删的过程中,有可能有一些点的度数小于 k k k)。
那么,我们需要操作多次,每次操作需要删去当前连通块中度数小于等于 k k k的点。删完之后,这个图不一定连通,所以要求出最大连通块的大小,用度数最小的点的度数和连通块的大小更新答案即可。
但求出最大连通块的大小的时间复杂度是 O ( n ) O(n) O(n)的,所以如果删完直接求的话,总时间复杂度是 O ( n 2 ) O(n^2) O(n2)的,会TLE。
那我们怎么处理呢?只需在操作的时候记录每次操作删去的点,然后从最后一次操作往第一次操作来一遍。这样的话,删点操作就变成了加点操作,用并查集即可解决。
总时间复杂度为 O ( ( n + m ) log ( n + m ) + m ⋅ α ( n ) ) O((n+m)\log(n+m)+m\cdot\alpha(n)) O((n+m)log(n+m)+m⋅α(n))。
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5,M=2e5;
int n,m,x,y,tot=0,vl=0,hv=1,d[M*2+5],l[M*2+5],r[N+5],ct[N+5],ot[N+5],fa[N+5],sum[N+5];
long long now=1e9,ans=0,ls[M+5];
vector<int>v[200005];
struct node{
int id,x;
bool operator<(const node ax)const{
return x>ax.x;
}
};
priority_queue<node>q;
void add(int xx,int yy){
l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
int find(int ff){
if(fa[ff]!=ff) fa[ff]=find(fa[ff]);
return fa[ff];
}
void dfs(int u){
for(int i=r[u];i;i=l[i]){
if(ot[d[i]]) continue;
int v1=find(u),v2=find(d[i]);
if(v1!=v2){
fa[v1]=v2;
sum[v2]+=sum[v1];
hv=max(hv,sum[v2]);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
++ct[x];++ct[y];
}
for(int i=1;i<=n;i++){
q.push((node){i,ct[i]});
fa[i]=i;sum[i]=1;
}
while(!q.empty()){
now=q.top().x;
ls[++vl]=now;
while(!q.empty()&&q.top().x<=now){
int u=q.top().id,x=q.top().x;
q.pop();
if(ct[u]!=x) continue;
ot[u]=1;
v[vl].push_back(u);
for(int i=r[u];i;i=l[i]){
if(ot[d[i]]) continue;
--ct[d[i]];
q.push((node){d[i],ct[d[i]]});
}
}
}
for(int i=vl;i>=1;i--){
for(int j=0;j<v[i].size();j++){
ot[v[i][j]]=0;
dfs(v[i][j]);
}
ans=max(ans,ls[i]*hv);
}
printf("%lld",ans);
return 0;
}
文章讲述了如何解决一个关于无向图的问题,目标是找到具有最大强度的连通块。方法涉及删除度数小于特定值的节点,并使用并查集优化求解过程,以降低时间复杂度到O((n+m)log(n+m)+m⋅α(n))。
1656

被折叠的 条评论
为什么被折叠?



