公式
C - 水やり / Watering 解説
by
C - 水やり / Watering 解説
by
physics0523
\(Q\) 回の水やりの後の水分量を問われているため、 \(Q\) 回の操作をそれぞれ行う必要はなく、操作をまとめて行ってその結果を求めればよいです。
もし \(Q=1\) であれば、頂点 \(x\) の部分木に \(d\) 加算するのは以下の要領で行えばよいです。
- 最初、全ての頂点に \(0\) が書かれているとする。
- 予め、頂点 \(x\) に \(d\) 加算する。(★)
- その後、根から順に以下の操作を行う。(この問題の制約で \(P_i < i\) なので、実際には頂点 \(1,2,\dots,N\) の番号順に操作を行えばよいです)
- 頂点 \(x\) に書き込まれている値を、頂点 \(x\) の(直接の)子すべてに加算する。
こうすると、頂点 \(x\) の部分木全体に \(d\) 加算されたことが分かります。
\(Q>1\) 、つまり加算が複数回発生してもやることはほとんど変わりません。
★ の部分を全ての加算について予め行っておくことで、部分木に対する加算を全部まとめて処理できます。
時間計算量は \(O(N+Q)\) です。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){
ll N,Q;
cin >> N >> Q;
vector<vector<ll>> chi(N);
for(ll i=1;i<N;i++){
ll P;
cin >> P;
chi[P-1].push_back(i);
}
vector<ll> res(N,0);
while(Q--){
ll X,D;
cin >> X >> D;
res[X-1]+=D;
}
for(ll i=0;i<N;i++){
if(i){cout << " ";}
cout << res[i];
for(auto &nx : chi[i]){
res[nx]+=res[i];
}
}cout << "\n";
return 0;
}
投稿日時:
最終更新:
