题目要求:
给定一个包含 n 个点(编号为 1∼n1∼n)的无向图,初始时图中没有边。
现在要进行 m 个操作,操作共有三种:
C a b
,在点 a 和点 b 之间连一条边,aa 和 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
,如果 aa 和 bb 在同一个连通块中,则输出 Yes
,否则输出 No
。
对于每个询问指令 Q2 a
,输出一个整数表示点 a 所在连通块中点的数量
每个结果占一行。
数据范围
1≤n,m≤1051≤n,m≤105
输入样例:
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
输出样例:
Yes
2
3
具体思路:
const int N=1005 //指定并查集所能包含元素的个数(由题意决定)
int pre[N]; //存储每个结点的前驱结点
int rank[N]; //树的高度
void init(int n) //初始化函数,对录入的 n个结点进行初始化
{
for(int i = 0; i < n; i++){
pre[i] = i; //每个结点的上级都是自己
rank[i] = 1; //每个结点构成的树的高度为 1
}
}
int find(int x) //查找结点 x的根结点
{
if(pre[x] == x) return x; //递归出口:x的上级为 x本身,则 x为根结点
return find(pre[x]); //递归查找
}
int find(int x) //改进查找算法:完成路径压缩,将 x的上级直接变为根结点,那么树的高度就会大大降低
{
if(pre[x] == x) return x; //递归出口:x的上级为 x本身,即 x为根结点
return pre[x] = find(pre[x]); //此代码相当于先找到根结点 rootx,然后 pre[x]=rootx
}
bool isSame(int x, int y) //判断两个结点是否连通
{
return find(x) == find(y); //判断两个结点的根结点(即代表元)是否相同
}
void join(int x,int y)//将两个节点合并
{
int a=find(x);
int b=find(y);
fa[a]=b;
p[b]+=p[a];
}
bool join(int x,int y)
{
x = find(x); //寻找 x的代表元
y = find(y); //寻找 y的代表元
if(x == y) return false; //如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并,返回 false,表示合并失败;否则,执行下面的逻辑
if(rank[x] > rank[y]) pre[y]=x; //如果 x的高度大于 y,则令 y的上级为 x
else //否则
{
if(rank[x]==rank[y]) rank[y]++; //如果 x的高度和 y的高度相同,则令 y的高度加1
pre[x]=y; //让 x的上级为 y
}
return true; //返回 true,表示合并成功
}
具体代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m,a,b,fa[N], p[N];
string s;
void init()
{
for (int i=1; i<=n; i++)
{
fa[i] = i;
p[i] = 1;
}
}
int find(int x)
{
if(fa[x]==x)
return x;
else
return fa[x]=find(fa[x]);
}
//将两个节点合并
void join(int x,int y)
{
int a=find(x);
int b=find(y);
fa[a]=b;
p[b]+=p[a];
}
//检查两个节点是否联通
bool ask(int a,int b)
{
return find(a)==find(b);
}
int main()
{
scanf("%d%d",&n,&m);
init();
while(m--)
{
cin>>s;
if(s=="C")
{
scanf("%d%d",&a,&b);
if(!ask(a,b)) join(a,b);
}
else if(s=="Q1")
{
scanf("%d%d",&a,&b);
ask(a,b) ? printf("Yes\n") : printf("No\n");
}
else
{
scanf("%d",&a);
printf("%d\n",p[find(a)]);
}
}
return 0;
}