CF1167C News Distribution 带权并查集

https://codeforces.com/contest/1167/problem/C

题意:n个用户有m个分组,每个用户可以在多个分组里出现,也允许某个分组为空。每个用户可以把消息传递到同组的每个人,求每个用户最多把消息传递给多少个人。

思路: 带权并查集,一棵树上的任意一个人都可以把消息传递给树上的其他所有人。 rk数组维护该点所属的树拥有多少个结点(包括root)。 输出每个结点的rk值即为答案

 

 
 

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
int pa[maxn];
int rk[maxn];

int find(int x){ return pa[x]==x? x:pa[x]=find(pa[x]); } void unite(int a,int b){ a=find(a),b=find(b); if(a==b) return; if(rk[a]<rk[b]) { pa[a]=b; rk[b]+=rk[a]; } else{ pa[b]=a; rk[a]+=rk[b]; } } int main(){ //freopen("datain.txt", "r", stdin); ios::sync_with_stdio(0); cin.tie(0); int n,m; cin>>n>>m; for(int i=0;i<n;i++) pa[i]=i,rk[i]=1; for(int i=0;i<m;i++){ int k;cin>>k; if(k==0) continue; int last=-1,cur; cin>>last; last--; for(int j=1;j<k;j++){ cin>>cur; cur--; unite(cur,last); } } for(int i=0;i<n;i++){ cout<<rk[find(i)]<<' '; } cout<<endl; }

 

本题也可以使用dfs解决,即使用dfs求每个连通分量的结点数。

可以使用邻接表存图dfs。

每次dfs遍历到的结点在cc数组中标记为id,表示这是第id个连通分量,再在rk数组中存储第id个连通分量的结点数


#include<bits/stdc++.h>
using namespace std; typedef long long ll; const int maxn=1e6+5; vector<int> g[maxn]; int cc[maxn],rk[maxn]; int id; int n,m; int cnt; void dfs(int x){ if(cc[x]) return ; cc[x]=id; cnt++; for(auto y:g[x]) dfs(y); return ; } int main(){ //freopen("datain.txt", "r", stdin); ios::sync_with_stdio(0); cin.tie(0); cin>>n>>m; for(int i=0;i<m;i++){ int k; cin>>k; int last,x; if(!k) continue; cin>>last; last--; for(int j=0;j<k-1;j++){ cin>>x; x--; g[x].push_back(last); g[last].push_back(x); } } for(int i=0;i<n;i++){ if(!cc[i]) cnt=0,id

转载于:https://www.cnblogs.com/hanker99/p/10968444.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值