並查集的操做有三步,初始化,查找祖先與合併。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; }