【背景】
朋友圈有时会传播谣言。
【问题描述】
现在有n个人、m个朋友圈,这n个人的id分别是1-n。大部分人都加入了一个或多个朋友圈,而有的人可能没进朋友圈,有的朋友圈里可能没有人。如果有一个人听到了谣言,他会把这个谣言发布到他加入的所有朋友圈中,所有看到这条谣言的人又会把这条谣言发布到他们所在的朋友圈中,这样谣言就会散布开来。
现在你得到了m个朋友圈中的人员名单,问你对于n个人中的每一个人,如果这个人散播谣言,那么最多会有多少个人听到谣言。
【输入】
第一行两个整数n,m
接下来m行
每行开头是一个整数r,表示这个朋友圈里有多少个人
之后有r个整数,表示这个朋友圈里的人的id
同一行的所有整数用空格隔开
【输出】
一行n个用空格隔开的整数,表示对于id为1,2,…,n的人散播谣言会让最多多少人听到
【输入输出样例1】
friends.in | friends.out |
7 5 3 2 5 4 0 2 1 2 1 1 2 6 7
| 4 4 1 4 4 2 2
|
【数据范围】
对于30%的数据:n,m<=10
对于60%的数据:n,m<=1000
对于100%的数据:n,m<=10^6,∑ci<=10^6,朋友圈中不会有两个相同的人
前置芝士 并查集https://www.cnblogs.com/hapjin/p/5478352.html
这道题cdcq刚开始数据范围给错了,以至于zqy巨佬没能AK(女装).对于此类关系问题,询问最多可以多少人之类,我们可以考虑用并查集(这显然是一道并查集裸题啊),虽然很简单,但我认为这是最基础的,所以来纪念一下;
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<cctype> 6 #include<algorithm> 7 #define fo(i,a,b) for(register int i=a;i<=b;i++) 8 #define fd(i,a,b) for(register int i=a;i>=b;i--) 9 10 using namespace std; 11 12 typedef long long ll; 13 14 const int maxn=1e6+10; 15 16 int n,m,fat[maxn],size[maxn],nx,ny,t; 17 18 inline int read(){ 19 int ans=0,c; 20 while(!isdigit(c=getchar())); 21 do ans=ans*10+c-'0'; 22 while(isdigit(c=getchar())); 23 return ans; 24 } 25 26 inline int get(int x){ 27 if(fat[x]==x) return x; 28 return fat[x]=get(fat[x]); 29 } 30 31 inline void merge(int x,int y){ 32 fat[get(y)]=fat[x]; 33 } 34 35 inline void init(){ 36 n=read(),m=read(); 37 fo(i,1,n) fat[i]=i,size[i]=1; 38 fo(i,1,m){ 39 t=read(); 40 if(t>=1){ 41 nx=read(); 42 nx=get(nx); 43 fo(j,2,t){ 44 ny=read(); 45 ny=get(ny); 46 if(ny!=nx){ 47 merge(nx,ny); 48 size[nx]+=size[ny]; 49 } 50 } 51 } 52 } 53 fo(i,1,n) printf("%d ",size[get(i)]); 54 } 55 56 int main(){ 57 //freopen("friends.in","r",stdin); 58 //freopen("friends.out","w",stdout); 59 init(); 60 return 0; 61 }
请放心食用