题目
给定一个包含 n 个点(编号为 1∼n)的无向图,初始时图中没有边。
现在要进行 m个操作,操作共有三种:
C a b
,在点 a 和点 b 之间连一条边,a 和 b 可能相等;Q1 a b
,询问点 a 和点 b 是否在同一个连通块中,a 和 b 可能相等;Q2 a
,询问点 a 所在连通块中点的数量;输入格式
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为
C a b
,Q1 a b
或Q2 a
中的一种。输出格式
对于每个询问指令
Q1 a b
,如果 a 和 b 在同一个连通块中,则输出Yes
,否则输出No
。对于每个询问指令
Q2 a
,输出一个整数表示点 a 所在连通块中点的数量每个结果占一行。
数据范围
1≤n,m≤105
输入样例:
5 5 C 1 2 Q1 1 2 Q2 1 C 2 5 Q2 5
输出样例:
Yes 2 3
代码
#include<bits/stdc++.h>
using namespace std;
vector<int> parents, ranks, cnt;
void init(int n) {
parents.resize(n);
ranks.resize(n, 1);
cnt.resize(n, 1);
for(int i= 0; i < n; ++i) {
parents[i] = i;
}
}
int find(int x) {
if(x != parents[x]) {
parents[x] = find(parents[x]);
}
return parents[x];
}
void merge(int x, int y) {
int xroot = find(x);
int yroot = find(y);
if(xroot == yroot) {
return;
}
if(ranks[xroot] < ranks[yroot]) {
parents[xroot] = yroot;
cnt[yroot] += cnt[xroot];
} else {
parents[yroot] = xroot;
cnt[xroot] += cnt[yroot];
}
if(ranks[xroot] == ranks[yroot] && xroot != yroot) {
ranks[yroot]++;
}
}
bool isconnect(int x, int y) {
return find(x) == find(y);
}
int get_size(int x) {
return cnt[x];
}
int main(){
int n, m;
cin>>n>>m;
init(n);
while(m--) {
string op;
cin >> op;
if(op =="C") {
int a, b;
cin >> a >> b;
merge(a, b);
}else if(op == "Q1"){
int a, b;
cin >> a >>b;
if(isconnect(a, b)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
} else if(op == "Q2"){
int a;
cin >> a;
cout << get_size(find(a)) << endl; // 传入a的父节点,返回a节点所在的连通块的数量
}
}
return 0;
}