公式
C - 水やり当番 / Watering Duty 解説
by
C - 水やり当番 / Watering Duty 解説
by
physics0523
印刷ページ
やりたいことは 前日の C 問題 とほぼ同じです。
imos法 と呼ばれる方法を用います。この方法を今回の問題に沿った形で説明します。
- 「 \(A_{L_i},A_{L_i+1},\dots,A_{R_i}\) に \(C_i\) を加算する」というクエリが沢山あり、これらをまとめて処理したい。
- まず、ひとつの加算を以下の形に変換する。
- \(A_{L_i}\) に \(C_i\) 加算する。
- \(A_{R_i+1}\) から \(C_i\) 減算する。
- 全ての加算の処理を終えた後、以下の通りに累積和を取る処理を行う。
- \(A_{i+1}\) に \(A_i\) を加算することを、 \(i\) の昇順に繰り返す。
このようにすることで、変換した後の加算が累積和を取った後に区間加算に対応していることがわかります。
理解の助けの為、具体例を示します。
- \(A_2,A_3,A_4\) に \(1\) を加算したいとする。
- \(A_2\) に \(1\) 加算、 \(A_5\) から \(1\) 減算と言い換えられる。この時点で \(A=(0,1,0,0,-1,0,\dots)\) です。
- \(A_3,A_4,A_5\) に \(10\) を加算したいとする。
- \(A_3\) に \(10\) 加算、 \(A_6\) から \(10\) 減算と言い換えられる。この時点で \(A=(0,1,10,0,-1,-10,\dots)\) です。
- これで全ての加算が完了したとする。
- \(A\) の累積和を取る。 \(A=(0,1,11,11,10,0,\dots)\) となり、所望の加算が実現していることが分かる。
全体の時間計算量は \(O(N+Q)\) です。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
int main(){
int N,Q;
cin >> N >> Q;
vector<int> res(N+2,0);
while(Q--){
int L,R,C;
cin >> L >> R >> C;
res[L]+=C;
res[R+1]-=C;
}
for(int i=1;i<=N;i++){
if(i>1){cout << " ";}
res[i]+=res[i-1];
cout << res[i];
}cout << "\n";
return 0;
}
投稿日時:
最終更新:
