连通块中点的数量

837. 连通块中点的数量 - AcWing题库

题目要求:

给定一个包含 n 个点(编号为 1∼n1∼n)的无向图,初始时图中没有边。

现在要进行 m 个操作,操作共有三种:

  1. C a b,在点 a 和点 b 之间连一条边,aa 和 b 可能相等;
  2. Q1 a b,询问点 a 和点 b 是否在同一个连通块中,a 和 b可能相等;
  3. Q2 a,询问点 a所在连通块中点的数量;

输入格式

第一行输入整数 n 和 m。

接下来 m行,每行包含一个操作指令,指令为 C a bQ1 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;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值