A - 伝説の団子食通 (Legendary Dango Eater) Editorial by DeltaStruct

平衡二分探索木解法

各クエリで以下のような処理を実装することでクエリあたり\(\mathrm{O}(N)\)で解くことが可能です。(証明は公式解説の小課題1にあります。)

ans,rem = 0,0
for a in A:
  rem = max(0,rem+a)
  ans += rem//K
  rem = rem%K

ここで、以下のように変形します。\(\mathrm{rem}\)が常に\(0\)以上\(2K\)未満となることから、\(\mathrm{rem}\)から\(K\)減算する操作が高々一回に抑えられます。

ans,rem = 0,0
for a in A:
  if a>0:
    rem += a%K
    ans += a//K
    if rem>=K:
      rem -= K
      ans += 1
  else:
    rem = max(0,rem+a)

\(S\)を\(\mathrm{rem}\)をキーとして\(\mathrm{ans}\)を持つ平衡二分探索木とします。各クエリについて適切なタイミングで\(S\)にそのクエリに対応するノードを挿入することで、以下のようなコードで上の処理を実現できます。

for a in A:
  if a>0:
    S.rem += a%K
    S.ans += a//K
    l,r = S.split(K)
    r.rem -= K
    r.ans += 1
    S = merge(r,l)
  else:
    S.rem += a
    l,r = S.split(0)
    l.rem = 0
    S = merge(l,r)

splitは\([(\)引数未満の\(\mathrm{rem}\)からなる平衡二分探索木\(),(\)引数以上の\(\mathrm{rem}\)からなる平衡二分探索木\()]\)を返す関数です。
\(K\)以上のものをsplitし、\(-K\)してmergeする操作の際に\(\mathrm{rem}\)の順序が壊れそうに見えますが、\(\mathrm{rem}\)として有り得る最大値が\(K-1+a \% K\)、最小値が\(a \% K\)であることから順序が保たれます。
よってmerge/split、\(\mathrm{rem}\),\(\mathrm{ans}\)への加算、\(\mathrm{rem}\)の\(0\)への更新が可能な平衡二分探索木を用いて解くことができます。
同じ左端を持つクエリのノードをまとめることで、計算量は\(\mathrm{O}((N + Q) \log \mathrm{min}(N, Q))\)となります。
RBSTを用いた実装例 (C++, 737ms)