KUPC2020Spring F ボタンの木
お題箱より。
解法
公式解説と逆になってしまいますが、与えられる を改めて と定義します。これが正である頂点は「過剰なので減らす必要がある」、負である頂点は「不足しているので増やす必要がある」ことになり、全ての を にするのが目標です。
適当に根を決め、木DPのように葉から操作していきます。実装方法は何通りかありそうですが、私の場合は以下のようにしました。
頂点 を操作する時には、
- 頂点 の子孫である(頂点 自身を除く)頂点 については、全て となっている。
- 頂点 自身については、 となっている。
という条件が満たされるまで操作をすることにします。具体的にどういう操作になるのか考えましょう。
まず頂点 の直接の子である頂点 は となっている可能性があるので、まずこれを にする必要があります。子の不足分の最大値と同じ回数だけ頂点 を操作します。
このとき、不足分が最大である子以外には余分に値を送ってしまうので、それを「押し返す」必要があります。この押し返しにかかるコストは後で計算します。
直接の子全てについて となったら、その時点での の値を確認します。これが正でなければこれで終わりですが、もし正であればさらにこれを親側に押し出す操作をします。このときやはり子には余分に値を送ってしまうので、「押し返し」が発生します。
押し返しのコストについて考えましょう。頂点 の親から余分に値 が送られた時に、頂点 より下の値を変えずにその を親側に送り返すためにかかる合計操作回数を とします。これは頂点 を操作する 回と、頂点 の全ての子 に入ってしまう をさらに押し返すための の合計として計算できます。
これを根まで続けると、「必ず目的を達成できる」という制約から根 についてちょうど となり、それまでの全ての操作回数の合計として答えが求められます。