并查集——优秀的找爹模板题

并查集的操做有三步,初始化,查找祖先与合并。ios

既然并查集是来查找祖先的,那么初始化就必然是让每一个点的祖先指向本身函数

for(int i=1;i<=n;++i) fa[i]=i;

查找操做就是不断地向上走,直到找到祖先为止spa

while(x!=fa[x]) x=fa[x];

合并操做就是把一个节点的祖先变为另外一个节点的祖先。code

fa[find(a)]=find(b);//其中find(x)为x的祖先

咱们需对路径进行压缩。blog

即当咱们通过找到祖先节点后,回溯的时候顺便将它的子孙节点都直接指向祖先,使之后的查找复杂度变回O(logn)甚至更低 ip

while(x!=fa[x]) x=fa[x]=fa[fa[x]];

完整代码:get

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-1);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-9;
ll pp=1000000007;
ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
ll read(){
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}//head

int n,m,p,x,y,z;
int fa[20005];


int find_die(int x)//找爹函数 
{
    while(fa[x]!=x) x=fa[x]=fa[fa[x]];
    //将它的子孙节点都直接指向祖先 
    return x;
}

void uni(int r,int k)//合并函数 
{
    fa[k]=r;
}

inline void print(int x,int y)//输出函数 
{
        if(find_die(x)==find_die(y)) cout<<"Y"<<endl;
        else cout<<"N"<<endl;
} 

int main()
{
    n=read(),m=read();
    rep(i,1,n)
        fa[i]=i;
    rep(i,1,m)
    {
        z=read(),x=read(),y=read();
        if(z==1)
        {
        int r1=find_die(x);
        int r2=find_die(y);
        if(r1!=r2) uni(r1,r2);
        }
        else if(z==2)
            print(x,y);
    }
    
    return 0;
}