并查集刷题

B. Islands

uva-1665

并查集求连通块。可以发现水是一年年降低的,但并查集不支持拆分,因此倒过来做,让水位每年升高。

先将所有点按照高度排序,用并查集保存连续块,让最高的点作为并查集的父节点。每一年:先将满足条件的点露出水面,然后遍历四周的露出水面的点,进行合并。

这里注意合并的方法,合并并查集的时候是让最高的点作为父节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1000 + 5;
const int maxt = 1e5 + 5;
int island[maxn][maxn];
int n, m, t;
int par[maxn * maxn]; // 并查集
int height[maxt];
int ans[maxt];

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, -1, 0, 1};

struct node {
int x, y;
int h;
};

node a[maxn * maxn];

bool comp(node a1, node a2)
{
return a1.h < a2.h;
}

int find(int x)
{
if (par[x] == x) return x;
else return find(par[x]);
}

bool merge(int x, int y)
{
int par_x = find(x);
int par_y = find(y);
if (par_x > par_y) {
par[par_y] = par_x;
return true;
}
else if (par_x < par_y) {
par[par_x] = par_y;
return true;
}
else return false;
}

int main()
{
// freopen("./data/b/1.in", "r", stdin);

int Z; scanf("%d", &Z);
while (Z--) {
scanf("%d%d", &n, &m);
memset(island, 0, sizeof(island));
memset(height, 0, sizeof(height));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &island[i][j]);
int s = i * m + j;
a[s].x = i;
a[s].y = j;
a[s].h = island[i][j];
}
}
scanf("%d", &t);
for (int i = 0; i < t; i++) scanf("%d", &height[i]);

memset(par, -1, sizeof(par));
sort(a, a + n * m, comp);

int k = n * m - 1;
int res = 0;
for (int i = t - 1; i >= 0; i--) {
if (a[k].h > height[i]) {
while (k >= 0 && a[k].h > height[i]) {
if (par[a[k].x * m + a[k].y] == -1) {
par[a[k].x * m + a[k].y] = a[k].x * m + a[k].y;
res++;
}
for (int j = 0; j < 4; j++) {
int newx = a[k].x + dx[j];
int newy = a[k].y + dy[j];
if (newx >= 0 && newx < n && newy >= 0 && newy < m && island[newx][newy] > height[i] && par[newx * m + newy] != -1) {
if (merge(newx * m + newy, a[k].x * m + a[k].y)) res--;
}
}
k--;
}
if (k < 0) {
while (i >= 0) {
ans[i] = res;
i--;
}
break;
}
}
ans[i] = res;
}

// print ans
for (int i = 0; i < t; i++) {
printf("%d ", ans[i]);
}
printf("\n");
}

return 0;
}