---
id: 2DRQ
title: "2D Range Queries"
author: Benjamin Qi
prerequisites: 
 - Platinum - Range Update Range Query
description: "Extending Range Queries to 2D (and beyond)."
frequency: 1
---

export const metadata = {
  problems: {
    bitSam: [
      new Problem("CSES", "Forest Queries II", "1739", "Easy", false, ["2D BIT"], "[thecodingwizard's implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/cses/Forest%20Queries%20II.cpp)"),
    ],
    bit: [
      new Problem("DMOJ", "Crowded Cities", "bfs17p6", "Normal", false, ["2D Max BIT"], ""),
      new Problem("IOI", "Pairs", "https://wcipeg.com/problem/ioi0722", "Normal", false, ["3D BIT"], ""),
    ],
    offSam: [
      new Problem("DMOJ", "Soriya's Programming Project", "dmopc19c7p5", "Normal", false, ["2D BIT"], ""),
    ],
    off: [
      new Problem("Plat", "Friendcross", "722", "Hard", false, ["2D BIT"], ""),
      new Problem("Plat", "Mowing the Field", "601", "Hard", false, ["2D BIT"], ""),
    ],
    seg: [
      new Problem("POI", "Tetris 3D", "https://szkopul.edu.pl/problemset/problem/OQjANSOOD_-c38gh8p6g3Gxp/site/?key=statement", "Hard", false, ["2D Seg"], ""),
      new Problem("ojuz", "IOI 2013 - Game", "IOI13_game", "Very Hard", false, ["2D Seg"], "Alternatively, use BBST in place of sparse segment tree (see Advanced - Treaps)"),
      new Problem("ojuz", "JOI - Golf", "JOI17_golf", "Very Hard", false, ["Seg"], ""),
    ],
  }
};

See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementations/content/data-structures/2D%20Range%20Queries%20(15.2)).

## 2D RMQ

<resources>
  <resource source="CF" title="retrograd - Multi-Dimensional RMQ" url="blog/entry/53810" starred></resource>
</resources>

 - GP of Serbia 2020 B

## 2D BIT

<problems-list problems={metadata.problems.bitSam} />

### Tutorial

<resources>
  <resource source="GFG" title="2D BIT" url="two-dimensional-binary-indexed-tree-or-fenwick-tree"></resource>
  <resource source="TC" title="Binary Indexed Trees" url="binary-indexed-trees"></resource>
</resources>

### Problems

<problems-list problems={metadata.problems.bit} />

<optional-content title="Range Update and Range Query in Higher Dimensions">

Lazy propagation on segment trees does not extend to higher dimensions. However, you can extend the 1D BIT solution to solve range increment range sum in higher dimensions as well! See [this paper](https://arxiv.org/pdf/1311.6093.pdf) for details.

 - USACO Camp - "Cows Play Global Thermonuclear War" (2D case)
 
</optional-content>

## 2D Offline Sum Queries

<problems-list problems={metadata.problems.offSam} />

The intended complexity is $O(N\log^2 N)$ with a good constant factor. This requires updating points and querying rectangle sums $N$ times for points with coordinates in the range $[1,N]$. However The 2D BITs mentioned above use $O(N^2)$ memory, which is too much. Since we know all of the updates and queries beforehand, we can reduce the memory usage while maintaining a decent constant factor.

### Idea 1: Use an unordered map instead of a 2D array.

Bad idea ... This gives $O(N\log^2N)$ memory and time and the constant factors for both are terrible.

### Idea 2: Compress the points to be updated so that you only need $O(N\log N)$ memory. 

This doesn't require knowing the queries beforehand.

  - [my 1D offline BIT](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIToff.h)
  - [my 2D offline BIT](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/2D%20Range%20Queries%20(15.2)/BIT2DOff%20(15.2).h)

It's a bit difficult to pass the above problem within the time limit. Make sure to use fast input (and not `endl`)!

  - [thecodingwizard's implementation with 2D offline BIT above](https://github.com/thecodingwizard/competitive-programming/blob/master/DMOJ/Soriyas%20Programming%20Project.cpp)

### Idea 3: Use divide & conquer with a 1D BIT

  - mentioned in [this article](https://robert1003.github.io/2020/01/31/cdq-divide-and-conquer.html)
  - [thecodingwizard's (messy) implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/DMOJ/Soriya%20Programming%20Project%201d%20BIT%20cdq%20dnc.cpp) based off above

### Problems

<problems-list problems={metadata.problems.off} />

## 2D Segment Tree

Basically a segment tree of (maybe sparse) segment trees (or BBSTs, see "Advanced - Treap").

<info-block title="Pro Tip">

This is **not** the same as [Quadtree](https://en.wikipedia.org/wiki/Quadtree). If the coordinates go up to $C$, then 2D segment tree queries run in $O(\log^2C)$ time each but some queries make Quadtree take $\Theta(C)$ time!

</info-block>

### Short Description

<resources>
  <resource source="CPH" title="28.2 (Sparse SegTree), 28.4 (2D)">brief description</resource>
  <resource source="USACO" title="Analysis - Mowing the Field" url="http://www.usaco.org/current/data/sol_mowing_platinum_jan16.html">code</resource>
</resources>

### Reducing Memory Usage

Naively, inserting $N$ elements into a sparse segment tree requires $O(N\log C)$, giving a memory bound of $O(N\log^2C)$ on 2D segment tree memory. This is usually too much for $N=10^5$ (although it sufficed for "Mowing the Field" due to the higher memory limit). 

To resolve this, reduce the memory usage of sparse segment tree while maintaing the same $O(N\log C)$ insertion time (see the solution for IOI Game below for details).

(implementation)

### Problems

Can also try the USACO problems from above.

<problems-list problems={metadata.problems.seg} />