7922: 江湖 并查集

发布时间 2023-04-30 09:20:29作者: CRt0729

描述

 

江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多少个弯,都认为是自己人。这样一来,江湖上就形成了一个一个的帮派,通过两两之间的朋友关系串联起来。而不在同一个帮派的人,无论如何都无法通过朋友关系连起来,于是就可以放心往死了打。但是两个原本互不相识的人,如何判断是否属于一个朋友圈呢?

我们对n个人用1~n编号,用a[i]存储i的“大哥”,如果一个人没有“大哥”,则a[i]=i(即大哥就是自己)。如n=5:

下标 1 2 3 4 5
3 4 5 4 5

说明:“1”号的大哥是“3”号,“3”号的大哥是“5”号,“5”号的大哥是自己,因此"5"号是“1”号和“3”号的老大,这三个人构成一个朋友圈。

现在给出n个人的若干个朋友圈,有m次询问,每次询问u和v是不是在同一个朋友圈里。

 

 

输入

 

第一行为正整数n和m(1<=n, m<=1000),表示有n个侠士(1~n编号),m次查询。

第二行有n个数a[i],a[i]表示是编号为“i”的大哥,在1~n之间。

接下来有m行,每行两个正整数u和v,(1<=u, v<=n, u≠v),表示待查询的两个侠士编号。

数据保证,每个人都最多只认一个大哥。

 

 

输出

 

对每次查询,如果在同一个朋友圈输出Yes,否则输出No

 

 

样例输入

 

5 3
3 4 5 4 5
1 3
4 2
1 4

样例输出

 

Yes
Yes
No

#include<bits/stdc++.h>
using namespace std; 
const int N = 1e5+10,inf = 0x3f3f3f3f,M = 2*1e4+10;
int f[N],a[N],maxn,x[M],y[M];
int n,ans,m;
int find(int x) //找到x的祖先
{
    if(f[x]!=x)f[x] = find(f[x]); //如果x的爹不是自己,那么去寻找爹中爹
    return f[x];
} 
void merger(int x,int y) //合并x和y两个集合
{
    int fx = find(x);
    int fy = find(y);
    if(a[fx]<a[fy])swap(fx,fy); //交换位置,保证fx所在的关系网人数是比较多的 
    a[fx] = a[fx] + a[fy];
    ans = max(ans,a[fx]);
    f[fy] = fx; //fy的祖先是fx 
}
int main()
{    
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>f[i];
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        if(find(x)==find(y))cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
     return 0;
}