D - 最寄りの消防車 / Nearest Fire Truck Editorial by admin
Claude 4.6 Opus (Thinking)Overview
Given \(N\) fire stations lined up on a straight line, for each of \(Q\) fire reports, we need to dispatch the closest available fire truck among those on standby. Since a dispatched fire truck can no longer be used afterward, we need to manage them dynamically.
Analysis
Key Observations
We need to find the “closest fire truck on standby” each time: For a fire location \(P_j\), we select the closest fire station among those that haven’t been dispatched yet. If distances are equal, we choose the one with the larger performance value \(S_i\), and if those are also equal, the one with the smaller index.
The coordinates \(X_i\) of fire stations are strictly increasing: All values are distinct. Because of this, for any fire location, there are at most 2 fire stations at the same distance (one on the left and one on the right).
One fire station is removed with each dispatch: We need a data structure that can efficiently search and delete elements while managing data dynamically.
Problem with the Naive Approach
Scanning all fire stations each time to find the closest one results in \(O(NQ)\), which amounts to roughly \(4 \times 10^{10}\) operations when \(N, Q\) are at most \(2 \times 10^5\), causing TLE.
Solution Strategy
Use a balanced binary search tree (sorted list) to manage the fire stations on standby in coordinate order. By performing binary search for fire location \(P_j\), we can find the closest candidate in \(O(\log N)\).
Algorithm
Data Structure Preparation: Store the fire stations on standby in a
SortedListas tuples \((X_i, -S_i, i)\). We use \(-S_i\) because when distances are equal, we want to prioritize the larger performance value (since tuple comparison prioritizes the smaller value, we negate the sign).Processing Each Fire Report:
- For fire location \(P_j\), find the insertion position
posusingbisect_left((P, -∞, -1)). - Check two candidates:
pos - 1(nearest candidate on the left) andpos(nearest candidate on the right). - Compute the comparison key \((|X_i - P_j|, -S_i, i)\) for each candidate and select the one with the smallest tuple.
- Minimum distance → Maximum performance value (smallest \(-S_i\)) → Smallest index
- Remove the selected fire station from the
SortedListand output the result.
- For fire location \(P_j\), find the insertion position
Why Two Candidates Suffice: Since all \(X_i\) are distinct, checking the left neighbor and right neighbor of the fire location in the sorted list covers all candidates with minimum distance. There can never be three or more fire stations at the same distance.
Concrete Example
With \(X = [2, 5, 8]\), \(S = [3, 1, 3]\) and fire location \(P = 5\):
- pos is at the position of \((5, ...)\) → candidates are pos-1 (coordinate 2) and pos (coordinate 5)
- Distances: coordinate 2 has \(|2-5|=3\), coordinate 5 has \(|5-5|=0\)
- The fire station at coordinate 5 (fire station 2) is dispatched
Complexity
- Time complexity: \(O((N + Q) \log N)\)
- Initialization with \(N\) insertions (each \(O(\log N)\)), and for each query, binary search and deletion (each \(O(\log N)\))
- Space complexity: \(O(N)\)
Implementation Notes
Tuple Design: By using \((X_i, -S_i, i)\), we can directly leverage Python’s tuple comparison for priority determination. Distance comparison is done separately with
abs(X_i - P), and when distances are equal, the 2nd and 3rd elements of the tuple automatically handle tiebreaking.Search Key for
bisect_left: By using(P, -∞, -1), if a fire station with coordinate exactly \(P\) exists,pospoints to that position; otherwise, it points to the smallest coordinate greater than \(P\). This way, we only need to check the two positionspos-1andpos.sortedcontainers.SortedList: This is not in Python’s standard library, so we usesortedcontainers. It is often available in Python environments for competitive programming.Source Code
import sys
from sortedcontainers import SortedList
def main():
input_data = sys.stdin.buffer.read().split()
idx = 0
N, Q = int(input_data[idx]), int(input_data[idx+1])
idx += 2
X = [0] * N
S = [0] * N
for i in range(N):
X[i] = int(input_data[idx])
S[i] = int(input_data[idx+1])
idx += 2
# We need to efficiently find the closest available fire station to a given point.
# On ties in distance, pick highest S, then smallest index.
# We'll use a SortedList of (X[i], -S[i], i) for available stations.
# For each query, we need to find candidates near P using binary search.
available = SortedList()
for i in range(N):
available.add((X[i], -S[i], i))
out = []
for _ in range(Q):
P = int(input_data[idx])
idx += 1
# Binary search for position of P in available
# We want to check the element just before and at the insertion point
pos = available.bisect_left((P, float('-inf'), -1))
best = None
best_key = None # (distance, -S[i], i)
# Check candidates around pos
for p in (pos - 1, pos):
if 0 <= p < len(available):
xi, neg_si, i = available[p]
dist = abs(xi - P)
key = (dist, neg_si, i)
if best_key is None or key < best_key:
best_key = key
best = (xi, neg_si, i)
# The above checks at most 2 candidates. But there could be ties in distance
# at positions further away. For example, if pos-1 and pos have the same distance,
# we handled it. But what if pos+1 also has the same distance?
# Actually, since X values are strictly increasing, at most 2 stations can be
# equidistant (one on each side). But after removals, the sorted list entries
# are a subset, so at most one on each side at closest distance.
# Wait, X are strictly increasing, so all X[i] are distinct. In the sorted list,
# keyed by (X[i], ...), X values are distinct. So bisect gives us at most
# one candidate on each side at minimum distance. That's correct.
out.append(str(best[2] + 1))
available.remove(best)
sys.stdout.write('\n'.join(out) + '\n')
main()
This editorial was generated by claude4.6opus-thinking.
posted:
last update: