//洛谷P3367
并查集算法也算是算法中的经典了,它可以用O(logn)的时间支持一张图中集合的合并与查询。
这里,我们首先用一个数组fa[x]来表示以x为编号的祖先的编号(*每一个点的初始祖先为它自身)。
然后就是并查集的重中之重:find()函数!!!
int find(int x){ if(x==fa[x]) return x; else return fa[x]=find(fa[x]); }
find(x)就是查询点x 所在集合的祖先,并更新fa[x]。
这里注意,如果没有fa[x]=find(fa[x]),而只是return find(fa[x])的话,操作久了,树就会退化成一个链,而失去其logn的时间复杂度,很容易T。
然后,是实现集合之间的合并:merge()
void merge(int x,int y){ if(find(x)!=find(y)) fa[find(x)]=fa[y]; }
这样就把x 所在集合的祖先接在y 所在的集合的祖先下面,其中fa[find(x)]=fa[y]也可写成fa[fa[x]]=fa[y]。
最后就是并查集的查询操作:query()
bool query(int x,int y){ if(find(x)==find(y)) return true; else return false; }
如果x,y祖先相同,那么他们就在一个集合中,反之则不然。
最后代码整合一下如下:
#include<algorithm> #include<iostream> #include<cstdio> #include<vector> #define maxn 10000 + 10 using namespace std; int n,m,opr,v,u; int fa[maxn]; int find(int x){ if(x==fa[x]) return x; else return fa[x]=find(fa[x]); } void merge(int x,int y){ if(find(x)!=find(y)) fa[find(x)]=fa[y]; } bool query(int x,int y){ if(find(x)==find(y)) return true; else return false; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { scanf("%d%d%d",&opr,&u,&v); if(opr==1) merge(u,v); else if(query(u,v)) printf("Y "); else printf("N "); } return 0; }