Last Day Where You Can Still Cross

hard union find grid reverse simulation

Problem

A row × col grid starts as all land. Each day one cell from the 1-based list cells floods (turns to water): on day i the cell cells[i] becomes water. Return the last day on which you can still walk from any top-row cell to any bottom-row cell, stepping only on land in the four cardinal directions.

Inputrow = 3, col = 3, cells = [[1,2],[2,1],[3,3],[2,2],[1,1],[1,3],[2,3],[3,2],[3,1]]
Output3
After day 3 the flooded cells still leave a land path from the top row to the bottom row; on day 4 they no longer do.
Inputrow = 2, col = 2, cells = [[1,1],[2,1],[1,2],[2,2]]
Output2
After two floods a land path top-to-bottom still exists; the third flood breaks it.

def latestDayToCross(row, col, cells):
    n = row * col
    parent = list(range(n + 2))
    TOP, BOT = n, n + 1
    def find(x):
        while parent[x] != x:
            parent[x] = parent[parent[x]]
            x = parent[x]
        return x
    def union(a, b):
        parent[find(a)] = find(b)
    land = [[False] * col for _ in range(row)]
    dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    for d in range(len(cells) - 1, -1, -1):
        r, c = cells[d][0] - 1, cells[d][1] - 1
        land[r][c] = True
        cur = r * col + c
        if r == 0: union(cur, TOP)
        if r == row - 1: union(cur, BOT)
        for dr, dc in dirs:
            nr, nc = r + dr, c + dc
            if 0 <= nr < row and 0 <= nc < col and land[nr][nc]:
                union(cur, nr * col + nc)
        if find(TOP) == find(BOT):
            return d
    return 0
function latestDayToCross(row, col, cells) {
  const n = row * col, TOP = n, BOT = n + 1;
  const parent = Array.from({ length: n + 2 }, (_, i) => i);
  function find(x) {
    while (parent[x] !== x) { parent[x] = parent[parent[x]]; x = parent[x]; }
    return x;
  }
  function union(a, b) { parent[find(a)] = find(b); }
  const land = Array.from({ length: row }, () => new Array(col).fill(false));
  const dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]];
  for (let d = cells.length - 1; d >= 0; d--) {
    const r = cells[d][0] - 1, c = cells[d][1] - 1;
    land[r][c] = true;
    const cur = r * col + c;
    if (r === 0) union(cur, TOP);
    if (r === row - 1) union(cur, BOT);
    for (const [dr, dc] of dirs) {
      const nr = r + dr, nc = c + dc;
      if (nr >= 0 && nr < row && nc >= 0 && nc < col && land[nr][nc])
        union(cur, nr * col + nc);
    }
    if (find(TOP) === find(BOT)) return d;
  }
  return 0;
}
int latestDayToCross(int row, int col, int[][] cells) {
    int n = row * col, TOP = n, BOT = n + 1;
    int[] parent = new int[n + 2];
    for (int i = 0; i < n + 2; i++) parent[i] = i;
    boolean[][] land = new boolean[row][col];
    int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    for (int d = cells.length - 1; d >= 0; d--) {
        int r = cells[d][0] - 1, c = cells[d][1] - 1;
        land[r][c] = true;
        int cur = r * col + c;
        if (r == 0) union(parent, cur, TOP);
        if (r == row - 1) union(parent, cur, BOT);
        for (int[] dir : dirs) {
            int nr = r + dir[0], nc = c + dir[1];
            if (nr >= 0 && nr < row && nc >= 0 && nc < col && land[nr][nc])
                union(parent, cur, nr * col + nc);
        }
        if (find(parent, TOP) == find(parent, BOT)) return d;
    }
    return 0;
}
int find(int[] p, int x) {
    while (p[x] != x) { p[x] = p[p[x]]; x = p[x]; }
    return x;
}
void union(int[] p, int a, int b) { p[find(p, a)] = find(p, b); }
vector<int> par;
int find(int x) {
    while (par[x] != x) { par[x] = par[par[x]]; x = par[x]; }
    return x;
}
void uni(int a, int b) { par[find(a)] = find(b); }
int latestDayToCross(int row, int col, vector<vector<int>>& cells) {
    int n = row * col, TOP = n, BOT = n + 1;
    par.assign(n + 2, 0);
    for (int i = 0; i < n + 2; i++) par[i] = i;
    vector<vector<bool>> land(row, vector<bool>(col, false));
    int dr[] = {-1, 1, 0, 0}, dc[] = {0, 0, -1, 1};
    for (int d = cells.size() - 1; d >= 0; d--) {
        int r = cells[d][0] - 1, c = cells[d][1] - 1;
        land[r][c] = true;
        int cur = r * col + c;
        if (r == 0) uni(cur, TOP);
        if (r == row - 1) uni(cur, BOT);
        for (int k = 0; k < 4; k++) {
            int nr = r + dr[k], nc = c + dc[k];
            if (nr >= 0 && nr < row && nc >= 0 && nc < col && land[nr][nc])
                uni(cur, nr * col + nc);
        }
        if (find(TOP) == find(BOT)) return d;
    }
    return 0;
}
Time: O(row · col · α) Space: O(row · col)