第十一届蓝桥杯大赛软件类省赛:试题J:网络分析
原题:
利用并查集把相互连接的节点并入同一集合,因为并查集中实现了树的压缩,所以循环遍历查找在同一集合中节点的操作复杂度比较低。
#include <iostream>
using namespace std;
int arr[100001]; //记录集合信息
int num[100001] = { 0 }; //记录储存信息大小
int myfind(int i) { //实现查找祖先节点并缩短树高,使其子代节点向父节点集中
if (arr[i] < 0) //数组的初始化是祖先为自身,即节点值为下标
return i; //祖先为自身即返回
return arr[i] = myfind(arr[i]); //如果祖先不是自身,递归查找祖先,同时将当前节点和随后的父节点连接到祖先节点上,简化树
}
void join(int a, int b) { //将ab组合加入到集合中
int fa = myfind(a); //拿到a和b的祖先
int fb = myfind(b);
int temp = arr[fa] + arr[fb];
if (fa != fb) { //判断ab是否为同一祖先
if (fa < fb) { //如果fa更小,说明此集合节点更多
arr[fb] = fa; //就把fb为祖先的集合连接到fa上
arr[fa] = temp; //更新祖先fa的节点数量
}
else {
arr[fa] = fb;
arr[fb] = temp;
}
}
}
int main() {
for (int i = 1; i <= 100001; i++) { //初始化为-1,即全部为根节点
arr[i] = -1;
}
int n, m;
cin >> n >> m;
int op, a, b;
for (int i = 0; i < m; i++) {
cin >> op >> a >> b;
if (op == 1) {
join(a, b); //将a,b并入一个集合
}
else if (op == 2) {
int fa = myfind(a); //查找a的祖先
for (int i = 1; i <= n; i++) { //循环查找与a同祖先的节点
if (fa == myfind(i)) {
num[i] += b;
}
}
}
}
for (int i = 1; i <= n; i++) {
cout << num[i] << " ";
}
return 0;
}