并查集-银河英雄传说(nkoj1206)
题意分析
节点合并和查询是否在同一堆操作,同时维护节点间距,使用带序号的并查集
并查集(带序号)
首先了解并查集解决的问题:动态连通性问题,即把p和q所在的堆合并
,看p和q在不在同一堆
首先让所有的点分属不同的组:father[i]=i
然后最naive的基本操作:
int get_father(int x) {
return father[x] == x ? x : father[x] = get_father(father[x]);
}
void merge(int x, int y) {
x = get_father(x);
y = get_father(y);
if (x != y) {
father[x] = y;
}
}
然后几种可能的拓展操作:
- 维护堆大小(合并的时候父亲的堆增大)
void merge(int x, int y) {
x = get_father(x);
y = get_father(y);
if (x != y) {
father[x] = y;
size[y] += size[x];
}
}
- 维护序号(合并的时候儿子的rank变大,get_father时在路径压缩前更新rank)
int get_father(int x) {
if (father[x] == x) {
return x;
} else {
int tmp = get_father(father[x]);
rank[x] += rank[father[x]];
father[x] = tmp;
return father[x];
}
}
void merge(int x, int y) {
x = get_father(x);
y = get_father(y);
if (x != y) {
father[x] = y;
rank[x] += size[y];
size[y] += size[x];
}
}
本题维护序号即可,rank之差即是节点间距
代码
//
// Created by rv on 2018/4/20.
//
#include "iostream"
#include "cstdio"
using namespace std;
int T, i, j;
char ins;
struct UF {
int count;
int* father;
int* size;
int* rank;
UF(int t) {
count = t;
father = new int[t];
size = new int[t];
rank = new int[t];
for (int i = 0; i < t; i++) {
father[i] = i;
size[i] = 1;
rank[i] = 0;
}
}
int get_father(int x) {
if (father[x] == x) {
return x;
} else {
int tmp = get_father(father[x]);
rank[x] += rank[father[x]];
father[x] = tmp;
return father[x];
}
}
void merge(int x, int y) {
x = get_father(x);
y = get_father(y);
if (x != y) {
father[x] = y;
rank[x] += size[y];
size[y] += size[x];
}
}
int call(int x, int y) {
if (get_father(x) != get_father(y)) {
return -1;
} else {
return abs(rank[x] - rank[y]) - 1;
}
}
void print() {
printf("father: ");
for (int i = 0; i < count; i++) {
printf("%d ", father[i]);
}
printf("\n");
printf("size: ");
for (int i = 0; i < count; i++) {
printf("%d ", size[i]);
}
printf("\n");
printf("rank: ");
for (int i = 0; i < count; i++) {
printf("%d ", rank[i]);
}
printf("\n");
}
};
int main() {
// freopen("1206/data2.in", "r", stdin);
// freopen("data2.out", "w", stdout);
scanf("%d", &T);
UF uf(T + 1);
while(T--) {
scanf("%s%d%d", &ins, &i, &j);
// printf("%c %d %d\n", ins, i, j);
if (ins == 'M') {
uf.merge(i, j);
}
if (ins == 'C') {
printf("%d\n", uf.call(i, j));
}
// uf.print();
}
return 0;
}