并查集本身是一种树形的数据结构,用于处理不相交集合的合并以及查询问题,在使用中常以森林来表示
POJ1988并查集
http://poj.org/problem?id=1988
题意:
有N个方块,有p次操作 分为两种
1 M x y 为将编号为x的方块整体放在含y的方块整体上面
2 C x 询问 x下有多少个方块
讲解详见注释
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 30000 + 5;
int n;
int fa[N], rt[N], block[N];
void init()
{
for(int i = 1;i < N;i ++)
fa[i] = i, rt[i] = 0, block[i] = 1;
}
int getf(int x)
{
int fx = fa[x];
//如果不是根节点,则进行合并
if(fa[x] != x)
{
//继续找根
fx = getf(fa[x]);
//找到过程中更新 rt的信息,即每到一个点更新他到根的距离
rt[x] += rt[fa[x]];
}
fa[x] = fx;
return fa[x];
}
void Merge(int x,int y)
{
int dx = getf(x);
int dy = getf(y);
fa[dy] = dx;
//dy 变成了dx的子结点, 那么距离根的长度也要加上原来dx拥有的子结点
rt[dy] += block[dx];
//将子结点的所有块加进来
block[dx] += block[dy];
}
int main()
{
while(~scanf("%d",&n))
{
char op[2];
int t1, t2;
//初始化
init();
while(n --)
{
scanf("%s",op);
if(op[0] == 'M')
{
scanf("%d%d",&t1,&t2);
//合并t1, t2 即将t1整个箱子块放在t2上
//从树形结构上来说 t1将变成t2的父节点
Merge(t1, t2);
}
else
{
scanf("%d",&t1);
//t1 的下方块数等于 他所在的一棵树的所有块 减去在它上面的结点的数 再减去它本身 1
printf("%d\n",block[getf(t1)] - rt[t1] - 1);
}
}
}
return 0;
}