Codeforces487D - Conveyor Belts - 分塊、記憶化搜索

D. Conveyor Belts

題意: 給出一個二維 n×mn\times m 的傳送帶地圖,其中>字符表示當前位置 (x,y)(x,y) 傳送至 (x,y+1)(x,y+1)<表示傳送至 (x,y1)(x,y-1)^表示傳送至 (x1,y)(x-1,y)。現在有 qq 次詢問,詢問有兩種類型,其中A x y表示詢問在點 (xi,yi)(x_i,y_i) 處放置物品,最終會被傳送到哪?(物品如果陷入循環則輸出-1,否則物品到達邊界則結束),而C x y c表示修改地圖第 (x,y)(x,y) 座標位置的傳送帶爲c類型。

  • 1n,q1051\le n,q\le 10^5
  • 1m101\le m\le 10

題解: 考慮對 nn 分塊,暴力維護塊內每個點的最終位置(要麼邊界,要麼陷入塊內陷入循環,要麼跳到其它塊),這樣查詢和修改都是 O(nm)\mathcal{O}(\sqrt {nm})。維護最終位置的方法是用dp[x][y]表示點 (x,y)(x,y) 到達的最終位置,遞歸地記憶化搜索即可。

代碼:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
char s[maxn][12];
int pos[maxn], L[maxn], R[maxn], n, m, q;
pii dp[maxn][12];
pii dfs(int x, int y, int lim) {
    if (dp[x][y].first != 0 || dp[x][y].second != 0) return dp[x][y];
    pii res = {0, 0};
    if (s[x][y] == '<') {
        if (y == 1) res = {x, y-1};
        else if (s[x][y-1] == '>') res = {-1, -1};
        else res = dfs(x, y-1, lim);
    } else if (s[x][y] == '>') {
        if (y == m) return res = {x, y+1};
        else if (s[x][y+1] == '<') res = {-1, -1};
        else res = dfs(x, y+1, lim);
    } else if (s[x][y] == '^') {
        if (x == lim) res = {x-1, y};
        else res = dfs(x-1, y, lim);
    }
    return dp[x][y] = res;
}
int main() {
    scanf("%d%d%d", &n, &m, &q);
    int block = sqrt(n + 0.5);
    for (int i = 1; i <= n; i++) {
        scanf("%s", s[i]+1);
        pos[i] = (i-1) / block + 1;
    }
    int tot = n / block;
    if (n % block) tot++;
    for (int i = 1; i <= tot; i++) {
        L[i] = (i-1) * block + 1;
        R[i] = i * block;
        if (i == tot) R[i] = min(R[i], n);
        for (int j = L[i]; j <= R[i]; j++) {
            for (int k = 1; k <= m; k++) dp[j][k] = dfs(j, k, L[i]);
        }
    }
    while (q--) {
        char op[2], c[2];
        int x, y;
        scanf("%s%d%d", op, &x, &y);
        if (op[0] == 'C') {
            scanf("%s", c);
            s[x][y] = c[0];
            for (int i = L[pos[x]]; i <= R[pos[x]]; i++) {
                for (int j = 1; j <= m; j++) dp[i][j] = {0, 0};
            }
            for (int i = L[pos[x]]; i <= R[pos[x]]; i++) {
                for (int j = 1; j <= m; j++) dp[i][j] = dfs(i, j, L[pos[x]]);
            }
        } else if (op[0] == 'A') {
            while (1) {
                if (x == -1 && y == -1) break;
                if (x == 0 || y == 0 || x == n+1 || y == m+1) break;
                int tx = dp[x][y].first;
                int ty = dp[x][y].second;
                x = tx, y = ty;
            }
            printf("%d %d\n", x, y);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章