AcWing 837. 连通块中点的数量(查并集)

题目描述:

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

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

  1. C a b,在点 a 和点 b 之间连一条边,a 和 b 可能相等;
  2. Q1 a b,询问点 a 和点 b 是否在同一个连通块中,a 和 b 可能相等;
  3. 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≤10^5

输入样例:

5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5

输出样例:

Yes
2
3

思路:本题为查并集的模板,主要围绕查并集的基本操作。

集合初始化:将每个节点的祖宗节点等于他本身,初始联通点的大小为1。

for(int i=1;i<=n;i++)
 {
     v[i]=i;num[i]=1;
 }

寻找祖宗节点:由于只有只有祖宗节点的p[x]值等于他自己,当该节点不是祖宗节点时要向上寻找他的祖宗节点。同时进行路径压缩,将所有与根节点相连的节点变为叶子节点。

int find_(int x)
{
    if(v[x]!=x) v[x]=find_(v[x]);
    /*
    可以发现,每个集合中只有祖宗节点的p[x]值等于他自己,即:
    p[x]=x;
    */
    return v[x];//找到了便返回祖宗节点的值
}

集合合并:将右节点的祖宗节点赋为左节点的祖宗节点。同时更新右节点联通集的大小,即右=右+左。

void merge_(int l,int r)
{
    int x=find_(l),y=find_(r);
    v[x]=y;
    num[y]+=num[x];
}

判断是否在同一联通集:看他们的祖宗节点是否相等。

int ask(int l,int r)
{
    return find_(l)==find_(r);
}

代码如下:

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define endl 

#define N  100005
using namespace std;
const int inf=0x3f3f3f3f;
const double ex=1e-7;
const int mod=1e9+7;
int gcd(int a ,int b){ return b ? gcd(b,a%b) : a ;}
string st;
int v[N],num[N];
int find_(int x)
{
    if(v[x]!=x) v[x]=find_(v[x]);
    return v[x];
}
int ask(int l,int r)
{
    return find_(l)==find_(r);
}
void merge_(int l,int r)
{
    int x=find_(l),y=find_(r);
    v[x]=y;
    num[y]+=num[x];
}
signed main()
{ios
    int n,m,l,r,k;
    string op;
    cin >>n>>m;
    for(int i=1;i<=n;i++)
    {
        v[i]=i;num[i]=1;
    }
    while(m--)
    {
        cin >>op;
        if(op=="C")
        {
           cin >>l>>r;
           if(!ask(l,r))
           {
               merge_(l,r);
           }
        }else if(op=="Q1")
        {
           cin >>l>>r;
           if(ask(l,r))
           {
               cout <<"Yes"<<endl;
           }else{
               cout <<"No"<<endl;
           }
        }else{
           cin >>k;
           int ans=find_(k);
           cout <<num[ans]<<endl;
        }
    }
    return 0;
}
经验分享 程序员 微信小程序 职场和发展