UVa 1665 - Islands

链接

传送门

题意

给出\(n \times m, (1 \leq n, m \leq 1000)\)的矩阵,给出\(T,(1 \leq T \leq 100000)\)个询问,对于每个询问\(t_i\),输出比\(t_i\)大的数字组成的四连块的个数。

思路

离线操作,用dsu维护连通块。

代码

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
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 1010;
const int maxq = 100010;
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};
int a[maxn][maxn];
int fa[maxn * maxn], ans[maxq];

struct node {
int x, y, v;
bool operator < (const node& rhs) const {
return v > rhs.v;
}
} nd[maxn * maxn];

struct query {
int x, id;
bool operator < (const query& rhs) const {
return x > rhs.x;
}
} q[maxq];

int Find(int x) {
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}

int main() {
int t;
scanf("%d", &t);
while (t--) {
int n, m, num = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
a[i][j] = false;
scanf("%d", &nd[num].v);
nd[num].x = i, nd[num].y = j;
fa[num] = num;
++num;
}
}
sort(nd, nd + num);
int qn;
scanf("%d", &qn);
for (int i = 0; i < qn; ++i) {
q[i].id = i;
scanf("%d", &q[i].x);
}
sort(q, q + qn);
int p = 0, cnt = 0;
for (int i = 0; i < qn; ++i) {
while (p < num && nd[p].v > q[i].x) {
a[nd[p].x][nd[p].y] = true;
int u = nd[p].x * m + nd[p].y;
for (int j = 0; j < 4; ++j) {
int x = nd[p].x + dx[j], y = nd[p].y + dy[j];
if (x < 0 || x >= n || y < 0 || y >= m || !a[x][y]) {
continue;
}
int fu = Find(u), fv = Find(x * m + y);
if (fu != fv) {
fa[fu] = fv;
++cnt;
}
}
++p;
}
ans[q[i].id] = p - cnt;
}
for (int i = 0; i < qn; ++i) {
printf("%d ", ans[i]);
}
puts("");
}
return 0;
}