CSES - Restaurant Customers
Authors: Michael Cao, Neo Wang, Brad Ma, Alex Du, Aadit Ambadkar
In this problem, we're given 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 , where is the number of intervals that cover each point . We can do this by looping through each interval and increasing by for each index in .
This results in a time complexity (where ), which easily times out (think what happens when the interval is queried times).
We can do better. It's easy to see that an increment of (before computation) in causes all subsequent (after computation) to increase by . We can also "undo" this operation by adding to . 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 because the interval is inclusive - decrementing at point turns the interval to .
Example 1: Add two to each point in the interval
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 and one to each point in
Adding interval with increment point at and decrement at
0 | 0 | 2 | 0 | 0 | -2 |
Adding interval with increment point at and decrement at
0 | 1 | 2 | 0 | -1 | -2 |
After computation
0 | 1 | 3 | 3 | 2 | 0 |
In this problem, our is fixed at . As a result, when we encounter a starting point, we can increment by , and for an endpoint, decrement by . We actually cannot compute the prefix sum array directly since , and we will run out of memory when creating an array of size .
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][];for (int i = 0; i < n; i++) {
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++) {StringTokenizer cus = new StringTokenizer(read.readLine());
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 = 0max_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 timetmap = 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 leavestmap[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!