C - 退場する選手と順位表 / Eliminated Players and the Standings Editorial by admin
Gemini 3.1 Pro (Thinking)Overview
When players leave a line in a specific order, this problem asks us to quickly determine the position (counted from the left) of each player in the line just before they leave.
Analysis
If we naively simulate the process described in the problem — “remove an element from an array and shift the remaining elements to the left” (e.g., using Python’s list pop()) — each deletion takes \(O(N)\) time. Repeating this for all \(N\) players results in an overall time complexity of \(O(N^2)\), which will exceed the time limit (TLE) given the constraint \(N \le 2 \times 10^5\).
The key insight for solving this problem efficiently is a shift in perspective: instead of actually compressing the line, we fix each player’s initial position and manage whether they are “still in the line or not” using \(1\) and \(0\).
For example, let \(1\) represent the initial state where everyone is still in the line, and \(0\) represent the retired state. Then, just before a player retires, “what position from the left are they in?” is equivalent to “how many players (positions with value \(1\)) remain from the left end of the line up to that player’s initial position?”
In other words, we need to efficiently perform the following two operations: 1. Prefix sum query: Compute the sum of \(1\)s from the left end up to a given position. 2. Point update: Change the value at a given position from \(1\) to \(0\) (processing the retirement).
Data structures that can perform both of these operations in \(O(\log N)\) include the Binary Indexed Tree (BIT / Fenwick Tree) and Segment Tree. Here, we use a BIT due to its lightweight implementation.
Algorithm
Record initial positions: Create an array
posthat records the initial left-to-right position of the player with stamina value \(k\). While reading the input stamina values \(L_i\), recordpos[L_i] = i + 1(1-indexed).Initialize the BIT: Prepare a BIT of length \(N\). Since everyone is initially in the line, add \(1\) to every position (from \(1\) to \(N\)) to initialize it.
Process queries: For stamina values \(k = 1, 2, \ldots, N\) in order, perform the following:
- Retrieve the initial position of player \(k\):
p = pos[k]. - Using the BIT, compute the sum from position \(1\) to \(p\). This gives the answer — “what position from the left was the player in just before retiring?”
- Since player \(k\) retires, add \(-1\) to position \(p\) in the BIT, updating its value to \(0\).
- Retrieve the initial position of player \(k\):
Output: Output the computed answers in order.
Complexity
- Time complexity: \(O(N \log N)\)
- Recording the initial positions and initializing the BIT takes \(O(N)\).
- For each player, the prefix sum query and point update using the BIT each take \(O(\log N)\). Repeating this \(N\) times gives \(O(N \log N)\).
- Overall, this is very fast and comfortably finishes within the time limit.
- Space complexity: \(O(N)\)
- The array
posfor storing players’ initial positions and the arraybitfor the BIT data each use \(O(N)\) memory.
- The array
Implementation Notes
BIT indexing: Due to the bit manipulation property (
i & -i) used by BITs, implementing with 1-indexed arrays results in very clean code.Fast I/O: In Python, calling
input()repeatedly can cause slowdowns, so reading all input at once usingsys.stdin.read().split()can significantly reduce execution time. For output, it is also efficient to accumulate results as strings in a list and output them all at once using'\n'.join().Linear-time BIT initialization: If we initialize the BIT by calling
addwith \(1\) for each position, the initialization takes \(O(N \log N)\). However, by propagating each node’s value to its parent node as done in the reference solution, the initialization can be performed in \(O(N)\).Source Code
import sys
def solve():
input = sys.stdin.read
data = input().split()
if not data:
return
N = int(data[0])
L = [int(x) for x in data[1:]]
pos = [0] * (N + 1)
for i in range(N):
pos[L[i]] = i + 1
bit = [0] * (N + 1)
for i in range(1, N + 1):
bit[i] += 1
nxt = i + (i & -i)
if nxt <= N:
bit[nxt] += bit[i]
def add(idx, val):
while idx <= N:
bit[idx] += val
idx += idx & (-idx)
def query(idx):
s = 0
while idx > 0:
s += bit[idx]
idx -= idx & (-idx)
return s
ans = []
for k in range(1, N + 1):
p = pos[k]
ans.append(str(query(p)))
add(p, -1)
print('\n'.join(ans))
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3.1-pro-thinking.
posted:
last update: