bzoj1104 [POI2007]洪水pow
Description
\(AKD\) 市处在一个四面环山的谷地里。最近一场大暴雨引发了洪水,\(AKD\) 市全被水淹没了。\(Blue\) \(Mary\),\(AKD\) 市的市长,召集了他的所有顾问(包括你)参加一个紧急会议。经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放在某些被水淹的区域,而后抽干洪水。你手头有一张 \(AKD\) 市的地图。这张地图是边长为 \(m*n\) 的矩形,被划分为 \(m*n\) 个 \(1*1\) 的小正方形。对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是 \(AKD\) 市的一个组成部分。地图上的所有部分都被水淹没了。并且,由于这张地图描绘的地面周围都被高山所环绕,洪水不可能自动向外排出。显然,我们没有必要抽干那些非 \(AKD\) 市的区域。每个巨型抽水机可以被放在任何一个 \(1*1\) 正方形上。这些巨型抽水机将持续地抽水直到这个正方形区域里的水被彻底抽干为止。当然,由连通器原理,所有能向这个格子溢水的格子要么被抽干,要么水位被降低。每个格子能够向相邻的格子溢水,“相邻的”是指(在同一高度水平面上的射影)有公共边。
Input
第一行是两个数\(m,n(1\leq m, n\leq1000)\). 以下 \(m\) 行,每行 \(n\) 个数,其绝对值表示相应格子的海拔高度;若该数为正,表示他是AKD市的一个区域;否则就不是。请大家注意:所有格子的海拔高度其绝对值不超过 \(1000\) ,且可以为零.
Output
只有一行,包含一个整数,表示至少需要放置的巨型抽水机数目。
Sample Input
6 9
-2 -2 -1 -1 -2 -2 -2 -12 -3
-2 1 -1 2 -8 -12 2 -12 -12
-5 3 1 1 -12 4 -6 2 -2
-5 -2 -2 2 -12 -3 4 -3 -1
-5 -6 -2 2 -12 5 6 2 -1
-4 -8 -8 -10 -12 -8 -6 -6 -4
Sample Output
2
Solution
\(bzoj\) 的题意果然是经常描述不清啊...
我们取出所有的城市放在 \(S\) 集合中,从小到大枚举每个城市,从小到大排序从所有的元素中取出海拔小于等于当前城市海拔的元素,合并相邻元素,然后查询当前城市所在的联通块是否已经被覆盖,如果没有就在当前城市安上水泵。
附CE三连。
#include<bits/stdc++.h>
using namespace std;
#define N 1000008
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define INF 0x7fffffff
inline int read() {
int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}
const int mv[4][2] = { 1, 0, -1, 0, 0, 1, 0 ,-1 };
struct pointType {
int x, y, hei;
bool operator < (const pointType& b) const { return hei < b.hei; }
}s[N], t[N];
bool tag[N];
int h[1008][1008];
int n, m, cnt, ans;
int fa[N];
int find(int x) { return (fa[x] ^ x) ? fa[x] = find(fa[x]) : x; }
int main() {
n = read(), m = read();
rep(i, 1, n + 1) h[i][0] = h[i][m + 1] = INF; rep(i, 1, m + 1) h[0][i] = h[n + 1][i] = INF;
rep(i, 1, n * m) fa[i] = i;
rep(i, 1, n) rep(j, 1, m) {
h[i][j] = read();
if (h[i][j] > 0) s[++cnt] = pointType{ i, j, h[i][j] };
h[i][j] = abs(h[i][j]);
t[(i - 1) * m + j] = pointType{ i, j, h[i][j] };
}
sort(s + 1, s + 1 + cnt); sort(t + 1, t + 1 + n * m);
int j = 1;
rep(i, 1, cnt) {
for (; j <= m * n && t[j].hei <= s[i].hei; j++) {
int x = t[j].x, y = t[j].y;
rep(k, 0, 3) {
int nx = x + mv[k][0], ny = y + mv[k][1];
if (h[nx][ny] > h[x][y]) continue;
int f0 = find((nx - 1) * m + ny), f1 = find((x - 1) * m + y);
tag[f1] |= tag[f0], fa[f0] = f1;
}
}
int f = find((s[i].x - 1) * m + s[i].y);
if (!tag[f]) ans++, tag[f] = 1;
}
cout << ans;
return 0;
}