带权并查集
T1.银河英雄传说
题意分析:
题目中所说的列我们可以将其看成一个集合,其中每一艘战舰之间均有关系,由此可以得出,战舰之间的关系是具有传递性的,所以我们可以用并查集来建立战舰之间关系的树形结构
对于每次的询问,可以维护一个数组d,表示当前元素到集合代表的距离(边权为1)
所以,询问i与j之间相隔的战舰数量,实际可以看作:i与j之间的距离 - 1
所以,本题的重点在于维护d数组:
1.初始化:自己到自己的距离为0
2.查询:每次进行查询时,我们都需要将查询点的 d[x] 累加查询其祖先路径上所有的d
3.合并:将x集合合并在y集合,此时我们还需要一个size数组维护每个集合内的元素数量,并对d数组赋值
代码实现:
初始化:
void MakeSet() {
for (int i = 1; i < SIZE; i ++ ) {
fa[i] = i;
d[i] = 0;
size[i] = 1;
}
}
路径压缩:
int FindSet(int x) {
if (x == fa[x]) return x;
int root = FindSet(fa[x]);// 路径压缩时更新
d[x] += d[fa[x]]; // d[x], x直接指向树根的边权和
return fa[x] = root;
}
合并:
void UnionSet(int x, int y) {
x = FindSet(x), y = FindSet(y);
fa[x] = y;
d[x] = size[y];
size[y] += size[x];
size[x] = 0;
return;
}
扩展域并查集
T2.食物链
题意分析:
根据题目,A吃B, B吃C,C吃A
对于每一个元素,可以扩展成三个部分,本身,猎物,天敌
将它们分别放在(1, n), (n + 1, 2n),(2n + 1, 3n)
所以在判断元素x与y的关系时,有以下可能:
- 如果给出x与y是同类,那么x + n, y + n是同类;x + 2n, y + 2n是同类
2.如果x会吃y,那么y是x的猎物,所以有:
x + n与y是同类
x + 2n与y + n是同类
x与y + 2n是同类
代码实现:
void check(int d, int x, int y, int n) {
if (d == 2 && x == y) {
ans ++;
return;
}
if ((x > n) || (y > n)) {
ans ++;
return;
}
if (d == 2) {
// 如果x吃y,那么只能是x与y + 2n是同类
if (FindSet(x) == FindSet(y) || FindSet(x) == FindSet(y + n)) {
ans ++;
}
else {
UnionSet(x, y + n * 2);
UnionSet(x + n * 2, y + n);
UnionSet(x + n, y);
}
} else {
// 如果x与y是同类,那么只能是y与x是同类
if (FindSet(x + n) == FindSet(y) || FindSet(x + 2n) == FindSet(y)) {
ans ++;
}
else {
UnionSet(x, y);
UnionSet(x + n, y + n);
UnionSet(x + n * 2, y + n * 2);
}
}
}