城市排水

在一個n×nn×n的方塊城市中,座標爲(i,j)(i,j)的位置高度爲h[i,j]h[i,j],有mm個排水井,分別位於(xi,yi)(x_i,y_i)
在一場大雨中,每個位置的水都會往相鄰的積水更低的地方流動,如果無法排出將越積越高
排水井處永遠不會積水,水不會通過城市邊緣排出(可以理解爲城市邊緣是無限高的牆)
求每個位置的積水深度

輸入描述
第一行輸入一個整數TT,代表有TT組測試數據 對於每一組測試數據,第一行輸入22個整數n,mn,m,接下來nn行每行有nn個整數h[i,j]h[i,j]表示第ii行第jj列的高度,接下來mm行每行有兩個整數xi,yix_i,y_i,表示第ii個排水井的位置

輸出描述
對於每組測試數據,輸出nn行,每行nn個整數,第ii行第jj列表示(i,j)(i,j)處的積水深度

數據範圍
1T10001≤T≤1000
1n5001≤n≤500
1mn×n1≤m≤n×n
n×n6105\sum{n×n}≤6·10^5
1h[i,j]10001≤h[i,j]≤1000
1xi,yin1≤x_i,y_i≤n

輸出時每行末尾的多餘空格,不影響答案正確性

樣例輸入
2
4 1
1 2 3 4
2 3 4 3
3 4 3 2
4 3 2 1
2 2
5 2
2 2 3 2 2
2 2 3 3 3
3 3 2 2 2
2 3 2 1 1
2 3 2 1 1
4 1
3 3
樣例輸出
2 1 0 0
1 0 0 1
0 0 1 2
0 1 2 3
1 1 0 1 1
1 1 0 0 0
0 0 0 0 0
0 0 0 1 1
0 0 0 1 1

樣例解釋
第一組樣例的解釋:
Image
第二組樣例的解釋:

Image
首先考慮排水口,顯然排水口周圍高度非遞減的區域一定是乾的,可以bfs將這部分的水面高度更新爲的面高度,對與處於對角線的區域要單獨討論。(其實忽略也行,不過後面二分求高度會慢一點 )
然後對於沒更新的區域二分水面高度,檢查在當前水面高度是否高於鄰近已更新區域的水面高度,最後更新水面高度。
容易想錯的點是不能根據排水口的高度更新比排水口高度低的區域,因爲比排水口高度低的區域的水面高度會受到多個排水口的直接或間接影響。
爲了提高代碼效率,排水口和未更新區域要以地面從低到高順序搜索;用數組存儲標記數組vv標記過的位置以便還原。
時間複雜度爲O(n2logn2)O(n^2logn^2)

#include<bits/stdc++.h>

#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector<int>
#define pii pair<int,int>
#define mii unordered_map<int,int>
#define msi unordered_map<string,int>
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 505;
int n, m, h1[N][N], h2[N][N], T;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
bool v[N][N];
vector<pair<int, pii>> seq;
vector<pii > tmp;

inline bool check(int x, int y) {
    return x >= 1 && x <= n && y >= 1 && y <= n;
}

inline void bfs1(int x, int y) {
    if (h2[x][y])return;
    queue<pii > q;
    q.push({x, y}), h2[x][y] = h1[x][y];
    while (!q.empty()) {
        pii t = q.front();
        q.pop();
        repi(i, 0, 3) {
            int nx = t.fi + dx[i], ny = t.se + dy[i];
            if (!check(nx, ny) || h2[nx][ny] || h1[nx][ny] < h1[t.fi][t.se])continue;
            h2[nx][ny] = h1[nx][ny], q.push({nx, ny});
        }
        int nx = t.fi + 1, ny = t.se + 1;
        if (check(nx, ny) && h1[nx][ny] >= h1[t.fi][t.se] && !h2[nx][ny] &&
            (h1[t.fi + 1][t.se] <= h1[nx][ny] || h1[t.fi][t.se + 1] <= h1[nx][ny]))
            h2[nx][ny] = h1[nx][ny], q.push({nx, ny});
        nx = t.fi - 1, ny = t.se + 1;
        if (check(nx, ny) && h1[nx][ny] >= h1[t.fi][t.se] && !h2[nx][ny] &&
            (h1[t.fi - 1][t.se] <= h1[nx][ny] || h1[t.fi][t.se + 1] <= h1[nx][ny]))
            h2[nx][ny] = h1[nx][ny], q.push({nx, ny});
        nx = t.fi - 1, ny = t.se - 1;
        if (check(nx, ny) && h1[nx][ny] >= h1[t.fi][t.se] && !h2[nx][ny] &&
            (h1[t.fi - 1][t.se] <= h1[nx][ny] || h1[t.fi][t.se - 1] <= h1[nx][ny]))
            h2[nx][ny] = h1[nx][ny], q.push({nx, ny});
        nx = t.fi + 1, ny = t.se - 1;
        if (check(nx, ny) && h1[nx][ny] >= h1[t.fi][t.se] && !h2[nx][ny] &&
            (h1[t.fi + 1][t.se] <= h1[nx][ny] || h1[t.fi][t.se - 1] <= h1[nx][ny]))
            h2[nx][ny] = h1[nx][ny], q.push({nx, ny});
    }
}

inline bool bfs2(int x, int y, int h) {
    queue<pii > q;
    tmp.clear();
    q.push({x, y}), tmp.pb({x, y}), v[x][y] = true;
    while (!q.empty()) {
        pii t = q.front();
        q.pop();
        repi(i, 0, 3) {
            int nx = t.fi + dx[i], ny = t.se + dy[i];
            if (!check(nx, ny) || v[nx][ny] || h1[nx][ny] >= h)continue;
            if (h2[nx][ny]) {
                for (auto it:tmp)v[it.fi][it.se] = false;
                return false;
            }
            if (h2[nx][ny] != h)q.push({nx, ny}), tmp.pb({nx, ny}), v[nx][ny] = true;
        }
    }
    for (auto it:tmp)v[it.fi][it.se] = false;
    return true;
}

inline void change(int x, int y, int h) {
    queue<pii > q;
    q.push({x, y}), h2[x][y] = h;
    while (!q.empty()) {
        pii t = q.front();
        q.pop();
        repi(i, 0, 3) {
            int nx = t.fi + dx[i], ny = t.se + dy[i];
            if (!check(nx, ny) || h2[nx][ny])continue;
            if (h1[t.fi][t.se] <= h && h1[nx][ny] <= h) {
                h2[nx][ny] = h;
                if (h != h1[nx][ny])q.push({nx, ny});
            } else if (h1[nx][ny] >= h2[t.fi][t.se])h2[nx][ny] = h1[nx][ny], q.push({nx, ny});
        }
    }
}

inline void solve(int x, int y) {
    int l = h1[x][y], r = 1000;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (bfs2(x, y, mid))l = mid;
        else r = mid - 1;
    }
    change(x, y, l);
}

int main() {
    T = qr();
    while (T--) {
        n = qr(), m = qr();
        repi(i, 1, n)repi(j, 1, n)h2[i][j] = 0, v[i][j] = false;
        repi(i, 1, n) repi(j, 1, n)h1[i][j] = qr();
        seq.clear();
        repi(i, 1, m) {
            int x = qr(), y = qr();
            seq.pb({h1[x][y], {x, y}});
        }
        sort(seq.begin(), seq.end());
        for (auto it:seq) {
            int x = it.se.fi, y = it.se.se;
            if (v[x][y])continue;
            bfs1(x, y);
        }
        repi(i, 1, n)repi(j, 1, n)v[i][j] = false;
        seq.clear();
        repi(i, 1, n)repi(j, 1, n)if (!h2[i][j])seq.pb({h1[i][j], {i, j}});
        sort(seq.begin(), seq.end());
        for (auto it:seq) {
            int x = it.se.fi, y = it.se.se;
            if (!h2[x][y])solve(x, y);
        }
        repi(i, 1, n) repi(j, 1, n)printf("%d%c", h2[i][j] - h1[i][j], ce(j, n));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章