<p>You are given an <code>m x n</code> binary matrix <code>grid</code> where each cell is either <code>0</code> (empty) or <code>1</code> (occupied).</p>

<p>You are then given stamps of size <code>stampHeight x stampWidth</code>. We want to fit the stamps such that they follow the given <strong>restrictions</strong> and <strong>requirements</strong>:</p>

<ol>
	<li>Cover all the <strong>empty</strong> cells.</li>
	<li>Do not cover any of the <strong>occupied</strong> cells.</li>
	<li>We can put as <strong>many</strong> stamps as we want.</li>
	<li>Stamps can <strong>overlap</strong> with each other.</li>
	<li>Stamps are not allowed to be <strong>rotated</strong>.</li>
	<li>Stamps must stay completely <strong>inside</strong> the grid.</li>
</ol>

<p>Return <code>true</code> <em>if it is possible to fit the stamps while following the given restrictions and requirements. Otherwise, return</em> <code>false</code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/11/03/ex1.png" style="width: 180px; height: 237px;" />
<pre>
<strong>Input:</strong> grid = [[1,0,0,0],[1,0,0,0],[1,0,0,0],[1,0,0,0],[1,0,0,0]], stampHeight = 4, stampWidth = 3
<strong>Output:</strong> true
<strong>Explanation:</strong> We have two overlapping stamps (labeled 1 and 2 in the image) that are able to cover all the empty cells.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/11/03/ex2.png" style="width: 170px; height: 179px;" />
<pre>
<strong>Input:</strong> grid = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]], stampHeight = 2, stampWidth = 2 
<strong>Output:</strong> false 
<strong>Explanation:</strong> There is no way to fit the stamps onto all the empty cells without the stamps going outside the grid.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>m == grid.length</code></li>
	<li><code>n == grid[r].length</code></li>
	<li><code>1 &lt;= m, n &lt;= 10<sup>5</sup></code></li>
	<li><code>1 &lt;= m * n &lt;= 2 * 10<sup>5</sup></code></li>
	<li><code>grid[r][c]</code> is either <code>0</code> or <code>1</code>.</li>
	<li><code>1 &lt;= stampHeight, stampWidth &lt;= 10<sup>5</sup></code></li>
</ul>

class Solution:
    def possibleToStamp(self, grid: List[List[int]], stampHeight: int, stampWidth: int) -> bool:
        from itertools import accumulate
        
        # preprocessing for 2D range sum query
        def gen_row_col_prefix(grid):
            prefix = [[0] * (len(grid[0]) + 1)]
            for row in grid:
                row = list(accumulate(row, initial=0))
                for col_id in range(len(row)):
                    row[col_id] += prefix[-1][col_id]
                prefix.append(row)
            return prefix
        
        # query function
        def query_2d_range_sum(prefix, x1, y1, x2, y2):
            return prefix[x2+1][y2+1] - prefix[x2+1][y1] - prefix[x1][y2+1] + prefix[x1][y1]
        
        H, W = len(grid), len(grid[0])
        prefix = gen_row_col_prefix(grid)
        
        stamp_grid = [[0] * W for i in range(H)] # 1 represents valid stamp position
        for row_id in range(H):
            for col_id in range(W):
                if row_id < stampHeight - 1 or col_id < stampWidth - 1:
                    continue
                else:
                    cnt = query_2d_range_sum(prefix, row_id - stampHeight + 1, col_id - stampWidth + 1, row_id, col_id)
                    if cnt:
                        continue
                    else:
                        stamp_grid[row_id][col_id] = 1
        
        
        stamp_prefix = gen_row_col_prefix(stamp_grid)
        for row_id in range(H):
            for col_id in range(W):
                if grid[row_id][col_id] == 1: # it is occupied at first, ignored
                    continue
                cnt = query_2d_range_sum(stamp_prefix, row_id, col_id, 
                                         min(row_id + stampHeight - 1, H - 1), 
                                         min(col_id + stampWidth - 1, W - 1))
                if not cnt:
                    return False
        return True
66100