E - 本棚の整理 / Organizing the Bookshelf Editorial by admin
Claude 4.6 Opus (Thinking)Overview
This problem requires efficiently processing three types of operations on \(N\) shelves arranged in a row: “add one book to each shelf in an interval,” “reset a single shelf to zero books,” and “find the total number of books in an interval.”
Analysis
Problems with the Naive Approach
If we manage the number of books on each shelf using an array: - Operation 1 (range addition): Takes \(O(r - l + 1)\), worst case \(O(N)\) - Operation 3 (range sum): Takes \(O(r - l + 1)\), worst case \(O(N)\)
Since \(N, Q\) are at most \(2 \times 10^5\), the total \(O(NQ)\) is at most \(4 \times 10^{10}\), which will TLE.
Key Insight
We separate each shelf’s value into an “addition component” and an “adjustment component” for management.
- \(\text{add}[i]\) = cumulative number of times shelf \(i\) has been included in Operation 1
- \(\text{adj}[i]\) = adjustment value for shelf \(i\) (used for reset operations)
Then, the actual number of books on shelf \(i\) can be expressed as \(\text{add}[i] + \text{adj}[i]\).
Processing Each Operation
- Operation 1 \((l, r)\): Add \(+1\) uniformly to \(\text{add}[l..r]\) (range addition)
- Operation 2 \((p)\): To set the actual book count to \(0\), update \(\text{adj}[p] = -\text{add}[p]\) (point update)
- Operation 3 \((l, r)\): Compute \(\sum_{i=l}^{r}(\text{add}[i] + \text{adj}[i])\) (range sum)
This allows us to use data structures suited to each component.
Algorithm
Efficient Processing Using BIT (Fenwick Tree)
add component: Range addition + Range sum query
Using two BITs (\(B_1, B_2\)), we achieve range addition and range sum with the following formula:
\[\text{prefix\_sum}(x) = B_1[x] \times x - B_2[x]\]
When adding \(+1\) to the interval \([l, r]\): - In \(B_1\): add \(+1\) at \(l\), add \(-1\) at \(r+1\) - In \(B_2\): add \(+(l-1)\) at \(l\), add \(-r\) at \(r+1\)
adj component: Point update + Range sum query
Managed with a single standard BIT (\(B_3\)). When updating \(\text{adj}[p]\) in Operation 2, we compute the difference \(\Delta = \text{new adj}[p] - \text{old adj}[p]\) and apply it to the BIT. The current value of \(\text{adj}[p]\) is stored in a separate array adj_val.
Concrete Example
With 5 shelves, performing Operation 1 \((1, 3)\), Operation 1 \((2, 4)\), Operation 2 \((2)\), Operation 3 \((1, 4)\):
- After Operation 1: \(\text{add} = [1, 1, 1, 0, 0]\)
- After Operation 1: \(\text{add} = [1, 2, 2, 1, 0]\)
- Operation 2: \(\text{add}[2] = 2\), so set \(\text{adj}[2] = -2\)
- Operation 3: \((1+0) + (2+(-2)) + (2+0) + (1+0) = 1 + 0 + 2 + 1 = 4\)
Complexity
- Time complexity: \(O(Q \log N)\) (each operation calls BIT a constant number of times, and each BIT operation is \(O(\log N)\))
- Space complexity: \(O(N)\) (three BITs and the adjustment value array)
Implementation Notes
Point query for add: In Operation 2, we need to know the cumulative addition for shelf \(p\), so we compute it as \(\text{prefix\_sum}(p) - \text{prefix\_sum}(p-1)\).
Difference management for adj: Since a BIT is a data structure that cumulatively adds values, to “set” \(\text{adj}[p]\) to a new value, we add the difference from the old value to the BIT. This is why the auxiliary array
adj_valis needed.Fast input reading: In Python, we use
sys.stdin.buffer.read()and batch the output for faster I/O.Source Code
import sys
from math import sqrt
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
# sqrt decomposition approach
# Each position has a value = (number of type-1 additions that cover it) - (adjustments from type-2 resets)
#
# We maintain:
# - A BIT (Fenwick tree) for range-add (type 1) using difference array technique
# This tracks the cumulative additions from type 1 operations.
# - For type 2 (reset at position p), we need to know current value at p and subtract it.
# We can handle this by maintaining a separate "adjustment" array.
#
# Actually, let me think more carefully.
#
# Let add[i] = total number of type-1 operations that include position i (cumulative).
# Let adj[i] = adjustment value for position i (starts at 0).
# The actual value at position i = add[i] + adj[i].
#
# Type 1 (l, r): increment add[i] for all i in [l, r] by 1. (Range add)
# Type 2 (p): set adj[p] = -add[p] (so that actual value becomes 0). But adj[p] was something before.
# Actually: current value = add[p] + adj[p]. We want it to become 0, so adj[p] = -add[p].
# Type 3 (l, r): sum of (add[i] + adj[i]) for i in [l, r] = sum(add[l..r]) + sum(adj[l..r]).
#
# For add: we need range add and range sum. Use a BIT with range update/range query.
# For adj: we need point update and range sum. Use a simple BIT.
# BIT for range add, range sum (add array)
# Using two BITs B1, B2 such that prefix_sum(x) = B1[x]*x - B2[x]
B1 = [0] * (N + 2)
B2 = [0] * (N + 2)
def bit_update(bit, i, delta):
while i <= N:
bit[i] += delta
i += i & (-i)
def bit_query(bit, i):
s = 0
while i > 0:
s += bit[i]
i -= i & (-i)
return s
def range_add(l, r, val):
bit_update(B1, l, val)
bit_update(B1, r + 1, -val)
bit_update(B2, l, val * (l - 1))
bit_update(B2, r + 1, -val * r)
def prefix_sum_add(x):
return bit_query(B1, x) * x - bit_query(B2, x)
def range_sum_add(l, r):
return prefix_sum_add(r) - prefix_sum_add(l - 1)
# BIT for adj array (point update, range sum)
B3 = [0] * (N + 2)
def adj_update(i, delta):
while i <= N:
B3[i] += delta
i += i & (-i)
def adj_prefix_sum(i):
s = 0
while i > 0:
s += B3[i]
i -= i & (-i)
return s
def adj_range_sum(l, r):
return adj_prefix_sum(r) - adj_prefix_sum(l - 1)
# adj_val[i] stores the current adjustment for position i
adj_val = [0] * (N + 1)
out = []
for _ in range(Q):
t = int(input_data[idx]); idx += 1
if t == 1:
l = int(input_data[idx]); idx += 1
r = int(input_data[idx]); idx += 1
range_add(l, r, 1)
elif t == 2:
p = int(input_data[idx]); idx += 1
# current value at p = add[p] + adj_val[p], we want it to be 0
add_p = prefix_sum_add(p) - prefix_sum_add(p - 1)
new_adj = -add_p
delta = new_adj - adj_val[p]
adj_val[p] = new_adj
adj_update(p, delta)
else:
l = int(input_data[idx]); idx += 1
r = int(input_data[idx]); idx += 1
ans = range_sum_add(l, r) + adj_range_sum(l, r)
out.append(ans)
sys.stdout.write('\n'.join(map(str, out)) + '\n')
main()
This editorial was generated by claude4.6opus-thinking.