小花梨判连通(并查集+map+vector连用)
题目描述
小花梨给出n个点,让k位同学对这n个点任意添加无向边,构成k张图。小花梨想知道对于每个点i,存在多少个点j(包括i本身),使得i和j在这k张图中都是连通的。
输入
第一行输入两个正整数n和k,分别表示点的个数和同学数。
接下来分成k部分进行输入,每部分输入格式相同。
每部分第一行输入一个整数ai,表示第i位同学连边的数目。
接下来ai行,每行两个正整数u,v,表示第i位同学将点u和点v之间进行连接。
可能会存在重边或者自环。(1≤n≤100000,1≤k≤10,1≤u,v≤n,0≤ai≤200000)
输出
输出n行,第i行输出在k张图中都和编号为i的点连通的点的数目(包括i本身)
样例输入
复制样例数据
4 2
3
1 2
1 3
2 3
2
1 2
3 4
样例输出
2
2
1
1
ps:每一张图,找到每个点的祖先,如果这个点的每张图的祖先和另外一个点每张图的祖先都相同,则这个点在每一张图里都与另外一个点联通,map<vector<int>,int>,vector代表很多元素,只有对应位置全部相同才++;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int fa[N],num[N];
vector<int>zu[N];
map<vector<int>,int>p;
int Find(int x){
if(fa[x]==x) return x;
return fa[x]=Find(fa[x]);
}
void Merg(int x,int y){
int a=Find(x);
int b=Find(y);
if(a!=b){
if(num[a]>num[b]){
num[a]+=num[b];
fa[b]=a;
}
else {
num[b]+=num[a];
fa[a]=b;
}
}
return ;
}
int main()
{
int n,k;
cin>>n>>k;
for(int i=0;i<k;i++){
for(int j=1;j<=n;j++){
fa[j]=j;
num[j]=1;
}
int m;
int u,v;
scanf("%d",&m);
while(m--){
scanf("%d%d",&u,&v);
Merg(u,v);
}
for(int j=1;j<=n;j++){
zu[j].push_back(Find(j));//把每个点的祖先推进去
//cout<<Find(j)<<endl;
}
}
for(int i=1;i<=n;i++){
p[zu[i]]++;//如果zu[i]里对应位置元素全部相同,++;
//printf("%d\n",p[zu[i]]);
}
for(int i=1;i<=n;i++){
printf("%d\n",p[zu[i]]);
}
return 0;
}