注释版:
int pre[maxn],rnk[maxn]; //rnk[a] 表示以a为根的这棵树的高度
void init(int n)
{
for(int i=0;i<n;i++)
pre[i]=i,rnk[i]=0;
}
int find(int x)
{
int r=x;
while(pre[r]!=r) r=pre[r]; //找r的前导结点 根节点的前导结点是自己,即pre[r]==r时
int i=x,j;
while(i!=r) //路径压缩
{
j=pre[i]; //记录x的前导结点
pre[i]=r; //将i的前导结点设置为r根节点
i=j;
}
rnk[r]=2;
return r;
}
void join(int x,int y)
{
int a=find(x); //x的根结点为a
int b=find(y); //y的根结点为b
if(a==b) return;
if(rnk[a]<rnk[b]) pre[a]=b; //高度小的树接在高度更大的根节点下,那样两棵树的最大高度仍然不会变
else
{
pre[b]=a; //同理
if(rnk[a]==rnk[b]) rnk[a]++; //如果原来高度相同,任何一棵树接在任何一个根结点下面,最大高度都会+1
}
}
简洁版:
//并查集
int pre[maxn],rnk[maxn];
inline void init(int n) {for(int i=0;i<=n;i++) pre[i]=i,rnk[i]=0;}
inline int find(int x)
{
int r=x,i=x,j;
while(pre[r]!=r) r=pre[r];
while(i!=r) {j=pre[i];pre[i]=r;i=j;} rnk[r]=2;
return r;
}
inline void join(int x,int y)
{
int a=find(x),b=find(y);
if(a==b) return;
if(rnk[a]<rnk[b]) pre[a]=b;
else {pre[b]=a; if(rnk[a]==rnk[b]) rnk[a]++;}
}