D - 成績と補習 / Grades and Supplementary Lessons Editorial by admin
Claude 4.6 Opus (Thinking)Overview
Given \(N\) students whose scores are updated \(Q\) times, after each update we need to find the \(\lceil N/2 \rceil\)-th value (the baseline) in the sorted sequence, and answer how many students have scores strictly less than this baseline.
Analysis
Problem Setup
First, let’s confirm the definition of the baseline. When the scores of \(N\) students are sorted in ascending order, the \(\lceil N/2 \rceil\)-th value is the baseline. For example:
- When \(N = 5\): \(\lceil 5/2 \rceil = 3\) → the 3rd smallest
- When \(N = 4\): \(\lceil 4/2 \rceil = 2\) → the 2nd smallest
Students eligible for supplementary lessons are those whose scores are strictly less than the baseline (students with scores equal to the baseline are not eligible).
Naive Approach and Its Issues
If we re-sort all scores after every update, each sort takes \(O(N \log N)\), resulting in \(O(QN \log N)\) over \(Q\) queries. When \(N, Q\) can be up to \(2 \times 10^5\), this is too slow.
Idea for Optimization
If we can maintain the set of scores in a sorted state at all times, then deletion, insertion, k-th element retrieval, and counting elements less than a given value can all be done efficiently. This requires a data structure equivalent to a balanced binary search tree.
In Python, the SortedList from the sortedcontainers library provides exactly this, with each operation running in \(O(\log N)\).
Algorithm
- Initialization: Add all students’ scores to a
SortedList. Maintain each student’s current score in an array \(S\). - Precompute \(k = \lceil N/2 \rceil\).
- For each update \((T_j, V_j)\):
- Remove student \(T_j\)’s old score from the
SortedList. - Add the new score \(V_j\) to the
SortedList. - Update \(S[T_j]\) to \(V_j\).
- The \((k-1)\)-th element (0-indexed) of the
SortedListis the baseline. - Use
bisect_left(baseline)to find the number of elements less than the baseline. This is the number of students eligible for supplementary lessons.
- Remove student \(T_j\)’s old score from the
Concrete Example
For \(N=5\), scores \([50, 30, 70, 20, 60]\): - Sorted sequence: \([20, 30, 50, 60, 70]\) - \(k = 3\), so the baseline is \(50\) (index \([2]\) in 0-indexed) - Elements less than \(50\): \(20, 30\), which is \(2\) → \(2\) students need supplementary lessons
Now if student 3’s score changes from \(70 \to 40\): - Sorted sequence: \([20, 30, 40, 50, 60]\) - The baseline is \(40\) - Elements less than \(40\): \(20, 30\), which is \(2\) → \(2\) students need supplementary lessons
Complexity
- Time complexity: \(O((N + Q) \log N)\)
- Initialization involves \(N\) insertions (each \(O(\log N)\)), and each query involves deletion, insertion, index access, and binary search, each \(O(\log N)\)
- Space complexity: \(O(N)\)
- For storing the
SortedListand the score array
- For storing the
Implementation Notes
0-indexed vs 1-indexed conversion: \(k = \lceil N/2 \rceil\) is 1-indexed, so access the
SortedListwithsl[k-1].Tracking old scores: Since the old score must be removed from the
SortedListduring updates, always keep each student’s current score recorded in array \(S\).Using
bisect_left:sl.bisect_left(baseline)returns the number of elements less thanbaseline(elements equal tobaselineare not included). This directly gives the number of students eligible for supplementary lessons.Fast I/O: Since \(N, Q\) can be large, read all input at once with
sys.stdin.buffer.read(), and write all output at once with'\n'.join().Source Code
import sys
from sortedcontainers import SortedList
def main():
input_data = sys.stdin.buffer.read().split()
idx = 0
N = int(input_data[idx]); idx += 1
Q = int(input_data[idx]); idx += 1
S = [0] * (N + 1)
sl = SortedList()
for i in range(1, N + 1):
S[i] = int(input_data[idx]); idx += 1
sl.add(S[i])
out = []
k = (N + 1) // 2 # ceil(N/2), 1-indexed position
for _ in range(Q):
t = int(input_data[idx]); idx += 1
v = int(input_data[idx]); idx += 1
old_val = S[t]
sl.remove(old_val)
sl.add(v)
S[t] = v
# baseline is sl[k-1] (0-indexed)
baseline = sl[k - 1]
# count of elements strictly less than baseline
count = sl.bisect_left(baseline)
out.append(str(count))
sys.stdout.write('\n'.join(out) + '\n')
main()
This editorial was generated by claude4.6opus-thinking.