这是一题带权值的并查集问题,并在move过程中规定了x, y连边的方向,因此在优化的过程中要记下每个节点到根的相对位置,并通过路径压缩将每个节点挂在每堆的最顶上的元素(父节点)。用数组par纪录每个节点的父节点,数组far纪录每个节点到父节点的相对距离,数组stk纪录以某元素为父节点的堆的节点(方块)数。
本题中的关键在于find函数通过递归方式进行的路径压缩,find函数的递归实现是本题的中心,递归思想有效又简单的自上而下实现了相对位置的更新。
当要求输出时只需将总个数减去相对个数即可。
#include <cstdio>
const int MAXN = 30000;
int par[MAXN+2];
int far[MAXN+2];
int stk[MAXN+2];
void init()
{
for (int i = 1; i <= MAXN; i++) {
par[i] = i;
stk[i] = 1;
far[i] = 0;
}
}
int find(int x)
{
if (par[x] == x)
return x;
int t = find(par[x]);
far[x] += far[par[x]];
par[x] = t;
return t;
}
void unite(int x, int y)
{
x = find(x);
y = find(y);
if (x == y) {
return;
}
int tmp = stk[x];
stk[x] += stk[y];
stk[y] = 0;
far[y] = tmp;
par[y] = x;
}
int main()
{
int p;
scanf("%d", &p);
getchar();
init();
while (p--) {
int ch = getchar();
int x, y;
if (ch == 'M') {
scanf("%d%d", &x, &y);
unite(x, y);
}
else if (ch == 'C') {
scanf("%d", &x);
int sum = stk[find(x)];
printf("%d\n", sum - far[x] - 1);
}
getchar();
}
return 0;
}