C - 水やり当番 / Watering Duty 解説 by admin 印刷ページ
GPT 5.2 High概要
区間 \([L_i, R_i]\) に同じ値 \(C_i\) を加える操作を \(Q\) 回行ったあと、各位置の合計値をまとめて求める問題です。
考察
各日ごとに「\(L_i\) から \(R_i\) の全プランターに \(C_i\) を加える」を素直に実装すると、1 回の操作で最大 \(N\) 個更新することになり、最悪で \(O(NQ)\) になります。
制約は \(N, Q \le 2 \times 10^5\) なので、\(NQ\) は最大で \(4 \times 10^{10}\) となり、時間内に間に合いません(TLE)。
ここで重要な気づきは、「区間に一括加算」は 差分(増減の境界)だけ記録 すればよい、ということです。
例えば「区間 \([L, R]\) に \(C\) を加える」は、 - \(L\) から先は \(+C\) 増える - ただし \(R+1\) から先では増加を打ち消して \(-C\) する
と考えられます。
つまり配列 diff を用意して
- diff[L] += C
- diff[R+1] -= C
だけ行い、最後に左から累積和を取れば、各プランターの合計が復元できます。
アルゴリズム
- 長さ \(N+2\) の差分配列
diffを \(0\) で初期化する(\(R+1\) を安全に扱うために余裕を持たせる)。 - 各クエリ \((L, R, C)\) について以下を行う:
diff[L] += Cdiff[R+1] -= C
cur = 0として \(i=1\) から \(N\) まで順にcur += diff[i]- これがプランター \(i\) の最終的な水量
- 得られた \(N\) 個を出力する。
具体例
\(N=5\)、操作が「\([2,4]\) に \(+3\)」の場合:
- diff[2] += 3, diff[5] -= 3
diff の累積和を取ると
位置1: 0
位置2: 3
位置3: 3
位置4: 3
位置5: 0
となり、区間だけが正しく増えることが分かります。
計算量
- 時間計算量: \(O(N + Q)\)(各クエリは \(O(1)\)、最後の累積和が \(O(N)\))
- 空間計算量: \(O(N)\)(差分配列と結果配列)
実装のポイント
diff[R+1]を更新するため、配列サイズをN+2にして範囲外アクセスを避けます。入力が大きいので、Python では
sys.stdin.buffer.read()のような高速入力が有効です。本コードでは 1-indexed で扱い、出力用配列だけ 0-indexed に詰めています(
res[i-1] = cur)。ソースコード
import sys
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
if not data:
return
N, Q = data[0], data[1]
diff = [0] * (N + 2)
idx = 2
for _ in range(Q):
L = data[idx]; R = data[idx + 1]; C = data[idx + 2]
idx += 3
diff[L] += C
diff[R + 1] -= C
res = [0] * N
cur = 0
for i in range(1, N + 1):
cur += diff[i]
res[i - 1] = cur
sys.stdout.write(" ".join(map(str, res)))
if __name__ == "__main__":
main()
この解説は gpt-5.2-high によって生成されました。
投稿日時:
最終更新: