1.并查集三个操作 |------初始化(par[i]保存根节点的键值)
|-------合并(集合)
|-------查询(是否在同一集合)
2.注意退化的情况,会是复杂度增高,用rak[]数组记录树的高度,每次合并两个树的时候都把深度小的数合并到深度大的树上
3.注意每次使用并查集都要给并查集par[]初始化(void init(int n));
函数:
//用角标代表元素,par代表根节点的元素值
int par[MAX_N], rak[MAX_N];
//初始化n个元素
void init(int i) {
for(int i = 0; i < n; i++) {
par[i] = i;
rak[i] = 0;
}
}
//搜索树的根
int Find(int x) {
if(par[x] == x) {
return x;
} else {
return par[x] = Find(par[x]);//递归找根
}
}
//合并连个点
void unite(int x, int y) {
x = Find(x);
y = Find(y);
if(x == y) {
return;
} else {
if(rak[x] < rak[y]) {
par[x] = y;
} else {
par[y] = x;
if(rak[x] == rak[y]) rak[x]++;
}
}
}
//判断x和y是否属于同一个集合
bool same(int x, int y) {
return Find(x) == Find(y);
}
例题:
Description
In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations.
Input
1. "O p" (1 <= p <= N), which means repairing computer p.
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate.
The input will not exceed 300000 lines.
Output
Sample Input
4 1 0 1 0 2 0 3 0 4 O 1 O 2 O 4 S 1 4 O 3 S 1 4
Sample Output
FAIL SUCCESS
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef pair<int, int> P;
//#define LOCAL
#define INF 0x3f3f3f3f
#define MAX_N 1005
struct computer {
int number;//编号为角标
P coor;//坐标(x, y)
} comp[MAX_N], comp2[MAX_N];
int par[MAX_N], rak[MAX_N];
//返回两个点的距离
double Distance(int x, int y) {
return sqrt(((double)x * (double)x) + ((double)y * (double)y));
}
//并查集初始化
void init(int n) {
for(int i = 0; i < n; i++) {
par[i] = i;
rak[i] = 0;
}
}
//查根
int Find(int x) {
if(par[x] == x) return x;
else {
return par[x] = Find(par[x]);
}
}
//合并两个集合
void unite(int x, int y) {
x = Find(x);
y = Find(y);
if( x == y ) return;
if(rak[x] < rak[y]) {
par[x] = y;
} else {
par[y] = x;
if(rak[x] == rak[y]) rak[x]++;
}
}
//是否属于一个集合
bool same(int x, int y) {
return Find(x) == Find(y);
}
int main()
{
#ifdef LOCAL
freopen("b:\\data.in.txt", "r", stdin);
#endif
int N;
double d;
scanf("%d%lf", &N, &d);
init(N);//忘记了初始化,这bug也是不行不行滴
for(int i = 1; i <= N; i++) {
scanf("%d%d", &comp[i].coor.first ,&comp[i].coor.second);
comp[i].number = i;
}
char c;
int a, b;
int cnt = 0;
while(cin >> c) {
if(c == 'O') {
cin >> a;
comp2[cnt].coor = comp[a].coor;
// cout << comp2[cnt].coor.first << " " << comp2[cnt].coor.second << endl;
comp2[cnt++].number = comp[a].number;
//取修好的电脑的数量
if(cnt > 1) {
for(int i = 0; i < cnt - 1; i++) {
// cout << Distance(abs(comp[a].coor.first - comp2[i].coor.first), abs(comp[a].coor.second - comp2[i].coor.second)) << endl;
if(Distance(abs(comp[a].coor.first - comp2[i].coor.first), abs(comp[a].coor.second - comp2[i].coor.second)) <= d) {
//修好的两个电脑的距离小于最远距离,合并两个点
// cout << a << " " << comp2[i].number << endl;
unite(a, comp2[i].number);//把修好的,并且可以相连的电脑放在一个集合
}
}
}
}
else
{
//输入为S的时候
cin >> a >> b;//a电脑和b电脑相连吗
if(same(a, b))
cout << "SUCCESS" << endl;
else
cout << "FAIL" << endl;
}
}
return 0;
}