CSES Solutions - Forest Queries
Last Updated :
23 Jul, 2025
Given an N X N grid representing the map of a forest. Each square is either empty or contains a tree. The upper-left square has coordinates (1,1), and the lower-right square has coordinates (n,n). Your task is to process q queries of the form: how many trees are inside a given rectangle in the forest?
Examples:
Input: N = 4, grid = {{'.', '*', '.', '*'}, {'*', '.', '.*', '*'}, {'*', '*', '.', '.'}, {'*', '*', '*', '*'}}, queries = {{2, 2, 3, 4}, {3, 1, 3, 1}}
Output:
3
1
Explanation:
- The rectangle from (2, 2) to (3, 4) contains 3 trees: {{'.', '*', '*'}, {'*', '.', '.'}}.
- The rectangle from (3, 1) to (3, 1) contains 1 tree: {{'*'}}.
Input: N = 4, grid = {{'.', '*', '.', '*'}, {'*', '.', '.*', '*'}, {'*', '*', '.', '.'}, {'*', '*', '*', '*'}}, queries = {{1, 1, 2, 2}}
Output:
2
Explanation:
- The rectangle from (1, 1) to (2, 2) contains 2 trees: {{'.', '*'}, {'*', '.'}}.
Approach: To solve the problem, follow the below idea:
We can solve the problem using Precomputation Technique. Precompute the cumulative sum of trees for each subrectangle starting from (1,1) and ending at each cell (i,j). This allows us to answer queries in constant time. Create a prefix sum array, say prefixSum[][] such that prefixSum[i][j] stores the number of trees in the rectangle (1, 1) to (i, j). Now, to answer each query (x1, y1, x2, y2):
- number of trees = prefixSum[x2][y2] - prefixSum[x1-1][y2] - prefixSum[x2][y1-1] + prefixSum[x1-1][y1-1]
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
vector<vector<int> >
preprocess_forest(vector<vector<char> >& grid, int n)
{
// Create a prefix sum array
vector<vector<int> > prefix(n + 1,
vector<int>(n + 1, 0));
// Fill the prefix sum array
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
int value = (grid[i - 1][j - 1] == '*') ? 1 : 0;
prefix[i][j] = value + prefix[i - 1][j]
+ prefix[i][j - 1]
- prefix[i - 1][j - 1];
}
}
return prefix;
}
int count_trees_in_rectangle(vector<vector<int> >& prefix,
int x1, int y1, int x2, int y2)
{
// Adjust for 1-based indexing in the prefix array
return prefix[x2][y2] - prefix[x1 - 1][y2]
- prefix[x2][y1 - 1] + prefix[x1 - 1][y1 - 1];
}
int main()
{
// size of the grid and number of queries
int n = 4, q = 3;
vector<vector<char> > grid = { { '.', '*', '.', '.' },
{ '*', '.', '*', '*' },
{ '*', '*', '.', '.' },
{ '*', '*', '*', '*' } };
// Preprocess the grid to get the prefix sum array
vector<vector<int> > prefix
= preprocess_forest(grid, n);
vector<vector<int> > queries = { { 2, 2, 3, 4 },
{ 3, 1, 3, 1 },
{ 1, 1, 2, 2 } };
// Process each query
for (int i = 0; i < q; i++) {
int x1 = queries[i][0];
int y1 = queries[i][1];
int x2 = queries[i][2];
int y2 = queries[i][3];
cout << count_trees_in_rectangle(prefix, x1, y1, x2,
y2) << endl;
}
return 0;
}
Time Complexity: O(N2 + Q), where N is the number of rows or columns in grid and Q is the number of queries.
Auxiliary Space: O(N2)
Explore
Basics
Bit manipulation
DP for CP
Advanced