并查集详解
https://blog.csdn.net/sjystone/article/details/115406797
银河英雄传说 https://www.acwing.com/problem/content/240/
考点:维护每个点到跟节点的距离d[N]
题目要求将一列战舰接到另一列战舰的排尾,但在实现上,将集合接到另一个集合的排头
每次操作,需要实现被挪动的每个点到跟节点的距离,都需要加上挪到的数组的size
实现:
每个点存的距离d,是这个点到父节点的距离
若把a集合挪到b集合后 -> d[pa] = size[pb] size[pb] += size[pa] (d[pa]初始是0)
两艘战舰间的距离:
if ( d[x] != d[y] ) -> abs(d[x] - d[y] ) - 1
else -> 0
#include <iostream>
using namespace std;
const int N = 30010;
int p[N], d[N], s[N], m;
int find(int x)
{
if ( x != p[x] )
{
int root = find(p[x]); //递归到跟节点
d[x] += d[p[x]]; //回溯,从跟节点开始,d[x]等于x到父节点的距离加父节点到跟节点的距离
p[x] = root; //回溯,让每个点直接指向跟节点
}
return p[x];
}
int main()
{
cin >> m;
for ( int i = 1; i < N; i ++ ) //不能等于N,数组会越界,易错
{
d[i] = 0; //到跟节点的距离
s[i] = 1; //集合中点的数量
p[i] = i; //集合
}
while ( m -- )
{
int a, b;
char op[2];
cin >> op >> a >> b;
if ( op[0] == 'M' )
{
int pa = find(a), pb = find(b);
if ( pa != pb )
{
d[pa] = s[pb]; //pa到新跟节点的距离为s[pb],再用d[a]跟新a下面的点
s[pb] += s[pa]; //更新新集合的点的数量
p[pa] = pb;
}
}
else
{
int pa = find(a), pb = find(b);
if ( pa != pb ) cout << -1 << endl;
else cout << max(0, abs(d[a] - d[b]) - 1) << endl;
}
}
return 0;
}