题目描述:
小花梨给出?个点,让?位同学对这?个点任意添加无向边,构成?张图。小花梨想知道对于每个点?,存在多少个点?(包括?本身),使得?和?在这?张图中都是连通的。
输入描述:
第一行输入两个正整数?和?,分别表示点的个数和同学数。
接下来分成?部分进行输入,每部分输入格式相同。
每部分第一行输入一个整数??,表示第?位同学连边的数目。
接下来??行,每行两个正整数?, ?,表示第?位同学将点?和点?之间进行连接。
可能会存在重边或者自环。
(1 ≤ ? ≤ 100000,1 ≤ ? ≤ 10,1 ≤ ?, ? ≤ ?, 0 ≤ ?? ≤ 200000)
输出描述:
输出?行,第?行输出在?张图中都和编号为?的点连通的点的数目(包括?本身)
输入样例:
4 2
3
1 2
1 3
2 3
2
1 2
3 4
输出样例:
2
2
1
1
这里可以用并查集来处理联通性的问题,如果两个点是联通的那么一定 是 find(a) == find (b)
所以我们可以把每个点在 K 张图中的祖先节点都存起来,两个点在 k 张图中都连接,就意味着,两个点在所有 k 个图中的祖先节点都是一致的,这里我们可以用 vector+map 完成
#include<iostream>
#include<vector>
#include<map>
using namespace std;
int n,m,k;
int pre[100005];
vector<int> v[100005];
map<vector<int>,int> mp;
int find(int x){
if(pre[x]==x)
return pre[x];
else
return pre[x]=find(pre[x]);
}
void merge(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
int main(){
scanf("%d%d",&n,&k);
while(k--){//k 个图
for(int i=1;i<=n;i++)//初始化
pre[i]=i;
scanf("%d",&m);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
merge(a,b);
}
for(int i=1;i<=n;i++)//把第 t 个图的 i 的祖先存入 i 的祖先集合里
v[i].push_back(find(i));
}
for(int i=1;i<=n;i++)//把各个点在 k 个图中的祖先放入 map
mp[v[i]]++;
for(int i=1;i<=n;i++)
printf("%d\n",mp[v[i]]); // 各个点对应的祖先都相同的话,就是在 k 张图中都联通
return 0;
}