C - 退場する選手と順位表 / Eliminated Players and the Standings Editorial by admin
Claude 4.6 Opus (Thinking)Overview
When \(N\) players retire in order of increasing stamina value, the problem asks us to efficiently determine “what position from the left each player is among the remaining players” just before they retire. We use a Binary Indexed Tree (BIT / Fenwick Tree) to compute rankings quickly.
Analysis
Problem Setup
Players are initially lined up from left to right in order \(1, 2, \ldots, N\). Player \(i\) has stamina value \(L_i\), and players retire in the order of stamina values \(1, 2, \ldots, N\).
When a player with stamina value \(k\) retires, we know their original position (initial position). The problem is to determine “among the players still remaining, what position from the left is this player at.”
Naive Approach and Its Issues
A naive approach would be to remove a player from an array upon each retirement and use linear search to find their position among the remaining players. However, this requires up to \(O(N)\) operations per retirement, resulting in \(O(N^2)\) overall, which causes TLE for \(N = 2 \times 10^5\).
Key Insight
We realize that we need to quickly determine “how many players still remaining are to the left of (or at) a given position.” This is a problem of computing prefix sums while dynamically updating them, and a Binary Indexed Tree (BIT) is ideal for this.
Let’s consider a concrete example. For \(N = 5\), \(L = [3, 1, 4, 5, 2]\):
- Initial state: positions \(0, 1, 2, 3, 4\) have players \(1, 2, 3, 4, 5\) respectively (all remaining)
- The player with stamina \(1\) is player \(2\) (position \(1\)). Number of remaining players in positions \(0\) to \(1\) \(= 2\) → 2nd from the left
- Remove player \(2\). Next, the player with stamina \(2\) is player \(5\) (position \(4\)). Number of remaining players in positions \(0\) to \(4\) \(= 4\) → 4th from the left
- …and so on.
Algorithm
- Preprocessing: Compute
stamina_to_pos[k]= the initial position (0-indexed) of the player with stamina value \(k\). - BIT Initialization: Prepare a BIT of length \(N\) and set all positions to \(1\) (all players are remaining).
- Process in order of stamina value \(k = 1, 2, \ldots, N\):
- Retrieve the initial position
posof the player with stamina value \(k\). - Query the BIT for the prefix sum over interval \([0, \text{pos}]\). This corresponds to “what position from the left this player is among remaining players.”
- Update the BIT by \(-1\) at that position (retirement processing).
- Retrieve the initial position
- Output the computed rank for each \(k\).
BIT Operations
query(i): Returns the number of remaining players from position \(0\) to \(i\) in \(O(\log N)\).update(i, -1): Retires the player at position \(i\) (decreases the count by \(1\)). \(O(\log N)\).
Complexity
- Time complexity: \(O(N \log N)\) (\(O(N \log N)\) for BIT initialization, and for each retirement, query and update each take \(O(\log N)\), performed \(N\) times)
- Space complexity: \(O(N)\) (for the BIT and preprocessing arrays)
Implementation Notes
It is standard practice to manage the BIT as 1-indexed. In the code, internal
+1is applied to 0-indexed positions.By constructing
stamina_to_posas a reverse lookup table from “stamina value → initial position,” we can identify the target player’s position in \(O(1)\) when processing in order of increasing stamina value.In Python, I/O can easily become a bottleneck, so we read all input at once using
sys.stdin.buffer.read()and write all output at once using'\n'.join().Source Code
import sys
def main():
input_data = sys.stdin.buffer.read().split()
N = int(input_data[0])
L = [int(input_data[i + 1]) for i in range(N)]
# stamina_to_pos[k] = position (0-indexed) of the player with stamina k
stamina_to_pos = [0] * (N + 1)
for i in range(N):
stamina_to_pos[L[i]] = i # 0-indexed position
# BIT (Fenwick Tree) to count remaining players
# bit[i] represents sum over a range, initialized with 1 for each position
bit = [0] * (N + 1)
def update(i, delta):
# 1-indexed
i += 1
while i <= N:
bit[i] += delta
i += i & (-i)
def query(i):
# sum from index 0 to i (0-indexed), so 1-indexed 1 to i+1
s = 0
i += 1
while i > 0:
s += bit[i]
i -= i & (-i)
return s
# Initialize: all positions are occupied
for i in range(N):
update(i, 1)
out = []
for k in range(1, N + 1):
pos = stamina_to_pos[k] # 0-indexed original position
# How many players are still present at positions 0..pos (including this player)
rank = query(pos)
out.append(str(rank))
# Remove this player
update(pos, -1)
sys.stdout.write('\n'.join(out) + '\n')
main()
This editorial was generated by claude4.6opus-thinking.
posted:
last update: