(あとで)
medは得点が負にならない能力のかわりに得点を1回だけ0点にできる能力をもってると考えてもよくて、木を「能力発動前に到達」「能力発動後に到達」「行かず」の3色に塗り分けることを考えて、木DP
— ちゃっくに300円 (@yosupot) 2017年8月15日
これ見たときは「は??」という感想だったが、よーく考えてみると分かった。
(あ) v0 → 操作A → v1 → 操作A → v2 → 操作A → v3 ... → 操作A
操作A : スコアが負なら 0 にする
(い) 操作B → v0 → 操作B → v1 → 操作B → v2 → 操作B → v3 ... → 操作B
操作B : スコアを 0 にリセットすることができる
(う) 操作B → v0 → 操作B → v1 → 操作B → v2 → 操作B → v3 ... → 操作B ※ただしリセットは高々 1 回だけ
f(頂点 v, v の状態) = v 以下のサブツリーのスコアの最大値
(v, AR) = v でリセット後ということはその子ノードは訪れないかリセット後じゃないといけないので pleasure[v] + Σ f(子ノード, AR|NONE)
(v, NONE) = 子ノードも全部 NONE なので 0
(v, BR) = pleasure[v] はどうせリセットされるのでカウントしない。各子ノードは AR でも BR でも NONE でもよいので Σ f(子ノード, BR|AR|NONE)
ほう〜 こんなすっきりとなるのか〜
(accepted in practice)
class OwaskiAndTree { public: int maximalScore(vector <int> pa, vector <int> pl) { int N = pa.size()+1; VI br(N); VI ar(N); // 葉から順に配ると簡潔に書ける ... lhic さんの実装を参考にした for(int i=N-1; i>=0; i--) { ar[i] += pl[i]; ar[i] = max(ar[i], 0LL); if(i) { int pi = pa[i-1]; ar[pi] += ar[i]; br[pi] += max(br[i], ar[i]); } } return max(br[0], ar[0]); } };