1. 程式人生 > >bzoj1104 [POI2007]洪水pow

bzoj1104 [POI2007]洪水pow

har avi out net operator 如果 math 枚舉 註意

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;
}

bzoj1104 [POI2007]洪水pow