Problem:
G: トレジャーハンター (Treasure Hunter)

問題

財宝の山が N 個あり、それぞれの山は 1 から N までで番号づけられている。i 番目の山には価値 p_i のお宝が眠っており、このお宝はその山に訪れた時点で得ることができる。一度お宝を得るとその山からはお宝がなくなってしまうので、お宝はそれぞれ一度しか得ることはできない。

異なる山に移動するには必ず道を利用しなければならない。山と山の間には合計 N-1 本の道があり、i 番目の道は山 u_i と v_i を双方向に結んでいる。もしもどの道も問題なく通行可能であると仮定すると、任意の 2 つの山について相互に行き来可能であることが分かっている。

どの道も長らく誰も通行しておらず修復しないと渡れないため、i 番目の道について最初に渡る際には c_i 円を支払って工事し、通行可能にする必要がある。一度工事した道であればそれ以上お金を支払うことなく通行が可能である。

トレジャーハンターであるあなたは、道の工事費用の予算を W 円持っている。あなたの目的は、はじめに降り立つ山を任意に 1 つ決め、合計 W 円以下で道を工事して異なる山に移動することで、得られるお宝の価値の合計を最大化することである。あなたは最大でどれだけの価値を得られるだろうか？

なお、お宝を途中で換金することはできないため、お宝を工事費用として使用することはできないことに注意せよ。

入力形式

入力は以下の形式で与えられる。

N W
p_1 p_2 ... p_N
u_1 v_1 c_1
:
u_{N-1} v_{N-1} c_{N-1}

1 行目では、山の数 N と工事費用の予算 W が与えられる。

2 行目では、i 番目の山に眠っているお宝の価値 p_i が与えられる。

3 行目から N+1 行目では、道の情報が与えられる。2+i 行目は i 番目の道の情報を表しており、山 u_i と v_i の間に工事費用 c_i の道があることを表す。

制約

1 \leq N \leq 10^2

1 \leq W \leq 10^5

1 \leq p_i \leq 10^9

1 \leq u_i \lt v_i \leq N

i \neq j ならば u_i \neq u_j または v_i \neq v_j

1 \leq c_i \leq 10^5

与えられる入力は全て整数である

出力形式

得られるお宝の価値の合計の最大値を 1 行に出力せよ。末尾の改行を忘れないこと。

入力例 1

3 10
6 8 2
1 2 3
2 3 8

出力例 1

14

山 1 または山 2 に降り立ち、山 1 と山 2 を結ぶ道を工事し、山 1 と山 2 にあるお宝を得るのが最適である。工事費用の予算は 10 であるので、ふたつの道を両方とも工事することはできない。

入力例 2

3 15
10 10 12
1 2 6
1 3 4

出力例 2

32

お宝を全て得ることができる。

入力例 3

5 1
4 8 8 2 10
1 2 3
2 4 5
2 5 2
1 3 7

出力例 3

10

予算が不足しており、どの道も工事できない場合もある。

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable
import scala.io.StdIn._
object Main extends App {
  val Array(n, w) = readLine.trim.split(' ').map(_.toInt)
  val price = readLine.trim.split(' ').map(_.toLong)
  val nodes = Array.fill(n){Nil: List[Route]}
  for (_ ← 1 until n){
    val Array(u, v, c) = readLine.trim.split(' ').map(_.toInt)
    nodes(u - 1) ::= Route(v - 1, c)
    nodes(v - 1) ::= Route(u - 1, c)
  }
  val depth = Array.fill(n){Int.MaxValue}; depth(0) = 0
  val stack = mutable.Stack[Int](0)
  val parents = Array.fill(n){0}
  while(stack.nonEmpty){
    val current = stack.pop()
    for (Route(next, _) ← nodes(current) if depth(next) > depth(current)) {
      depth(next) = depth(current) + 1
      parents(next) = current
      stack.push(next)
    }
  }
  val childCount = Array.fill(n){1}
  def count(current: Int): Int = {
    for (Route(next, _) ← nodes(current) if depth(current) < depth(next)) childCount(current) += count(next)
    childCount(current)
  }
  count(0)
  for (i ← nodes.indices) nodes(i) = nodes(i).filter(r ⇒ depth(r.to) > depth(i)).sortBy(r ⇒ childCount(r.to))(Ordering.Int.reverse)
  val array = Array.fill(n){(Array.fill(w + 1){0L}, Array.fill(w + 1){0L}, Array.fill(w + 1){0L})}
  println(search(0, Array.fill(w + 1){0L})._3.max)

  def search(current: Int, state: Array[Long]): (Array[Long], Array[Long], Array[Long]) = {
    val (x, y, z) = array(current)
    nodes(current) match {
      case Route(first, firstCost)::t ⇒
        val (ix, iy, iz) = search(first, state)
        for (i ← (firstCost until ix.length).reverse) {
          x(i) = math.max(state(i), ix(i - firstCost)) + price(current)
          y(i) = iy(i - firstCost) + price(current)
          z(i) = math.max(iz(i), y(i))
        }
        for (i ← 0 until math.min(state.length, firstCost)) {
          x(i) = state(i) + price(current)
          y(i) = price(current)
          z(i) = math.max(iz(i), y(i))
        }
        for (Route (next, cost) ← t) {
          val (ax, _, az) = search(next, x)
          for (i ← z.indices) {
            z(i) = math.max (z(i), az(i))
          }
          for (i ← cost until x.length) {
            x(i) = math.max(x(i), ax(i - cost))
          }
          val (bx, _, _) = search(next, y)
          for (i ← cost until x.length) {
            y(i) = math.max (y(i), bx(i - cost))
          }
        }
        for (i ← z.indices) {
          z(i) = math.max (z(i), y(i))
        }
        (x, y, z)
      case Nil ⇒
        for (i ← x.indices) {
          x(i) = state(i) + price(current)
          y(i) = price(current)
        }
        (x, y, y)
    }
  }
  case class Route(to: Int, cost: Int)
  case class Road(a: Int, b: Int, cost: Long)
  implicit class Scope[T](val value: T) extends AnyVal {
    def let[A](@inline func: T ⇒ A): A = func(value)
    def also(@inline func: T ⇒ Unit): T = {func(value);value}
  }
}