CSES - Restaurant Customers

Authors: Michael Cao, Neo Wang, Brad Ma, Alex Du, Aadit Ambadkar

In this problem, we're given nn intervals with distinct start and end points, and we want to find the maximum number of intervals overlapping some point.

Solution

We can use prefix sums to determine the number of intervals that cover any particular point, and then find the maximum number in the sum.

A naïve approach is to create an array ctr\texttt{ctr}, where ctr[i]\texttt{ctr}[i] is the number of intervals that cover each point ii. We can do this by looping through each interval [a,b][a,b] and increasing ctr[i]\texttt{ctr}[i] by 11 for each index in a≤i≤ba \leq i \leq b.

This results in a O(nV)\mathcal{O}(nV) time complexity (where 0≤a≤b≤V0 \leq a \leq b \leq V), which easily times out (think what happens when the interval [0,V][0, V] is queried nn times).

We can do better. It's easy to see that an increment of xx (before computation) in arr[i]\texttt{arr}[i] causes all subsequent prefix[i...V]\texttt{prefix}[i...V] (after computation) to increase by xx. We can also "undo" this operation by adding −x-x to arr[i]\texttt{arr}[i]. This concept can be conceptualized through increment and decrement points. An increment point increases (and decrement decreases) all subsequent cells. Note that our decrement point is located at B+1B+1 because the interval is inclusive - decrementing at point BB turns the interval to [A,B)[A, B).

Example 1: Add two to each point in the interval [2,4][2, 4]

Our array after adding 2 at our increment (start) point (before computation)

0 0 2 0 0 0

Our prefix sum after adding 2 at our increment (start) point (and computing).

0 0 2 2 2 2

Our prefix sum after subtracting 2 at our decrement point (and computing).

0 0 2 2 2 0

Observe that this works for multiple intervals.

Example 2: Add two to each point in [2,4][2, 4] and one to each point in [1,3][1, 3]

Adding interval [2,4][2, 4] with increment point at 22 and decrement at 4+1=54+1=5

0 0 2 0 0 -2

Adding interval [1,3][1, 3] with increment point at 11 and decrement at 3+1=43+1=4

0 1 2 0 -1 -2

After computation

0 1 3 3 2 0

In this problem, our xx is fixed at 11. As a result, when we encounter a starting point, we can increment by 11, and for an endpoint, decrement by 11. We actually cannot compute the prefix sum array directly since V≤109V \leq 10^9, and we will run out of memory when creating an array of size VV.

Instead, we can either coordinate compress and compute the prefix sum over interesting intervals or sweep over the intervals while maintaining a running prefix sum.

Implementation 1

If we put the start and end points into a list and sort them, all we need to do is find the max sum of values over all prefixes of the list.

C++

#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> times;
for (int i = 0; i < n; i++) {
int start, end;
cin >> start >> end;

Java

If we use the same implementation as the C++ version, CSES will give a TLE verdict on test case 6.

import java.io.*;
import java.util.*;
public class Customers {
public static void main(String[] args) throws IOException {
BufferedReader read =
new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(read.readLine());
int[][] times = new int[2 * n][];

To fix this, we can use a TreeMap instead of a sorted array.

import java.io.*;
import java.util.*;
public class Customers {
public static void main(String[] args) throws IOException {
BufferedReader read =
new BufferedReader(new InputStreamReader(System.in));
TreeMap<Integer, Integer> times = new TreeMap<>();
int n = Integer.parseInt(read.readLine());
for (int i = 0; i < n; i++) {

Python

Warning!

Due to Python's high constant factor, this code may TLE on a couple test cases.

times = []
for _ in range(int(input())):
start, end = map(int, input().split())
times.append((start, 1))
times.append((end, -1))
times.sort()
curr_ppl = 0
max_ppl = 0

Since all arrival and leaving times are distinct, we can store if a given time is an arrival or departure, and sort all the arrival and leaving times in one array.

# Stores the change in the number of people at a specific time
tmap = dict()
times = []
for _ in range(int(input())):
start, end = input().split()
start = int(start)
end = int(end)
# tmap is 1 when person enters, -1 when person leaves
tmap[start] = 1

Implementation 2

Coordinate compress interval endpoints and only compute the prefix sum array for interesting intervals.

C++

#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> times;
for (int i = 0; i < n; i++) {
int start, end;
cin >> start >> end;

Python

Warning!

Due to Python's big constant factor, this code may TLE on a couple test cases.

n = int(input())
times = []
for _ in range(n):
start, end = map(int, input().split())
times.append((start, 1))
times.append((end + 1, -1))
times.sort()

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!