Problem:
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
});

F: リレー / Relay

問題文

湖に浮かぶ $N$ 個の小島からなるビワコという村がある．
ビワコ村には $N-1$ 本の簡単な作りの橋がある．
島には $0$ から $N-1$ まで，橋には $0$ から $N-2$ までの番号が付けられている．
$i$ 番の橋は $i+1$ 番の島と $p_i$ 番の島を直接つなぎ，長さは $w_i$ である．
村人はどの島の間もいくつかの橋を通って相互に移動できるようになっている．

ある村人の提案により，ビワコ村でリレー大会が開催されることとなった．
しかし，ビワコ村には閉路がなくトラックを用意できないため，
現在ある橋を $1$ つだけ掛け替えることによって閉路を作ろうと考えた．
この操作によって用意できる閉路のうち，長さが最大となるものの長さを求めなさい．

入力

$N$

$p_0 \ w_0$

$\vdots$

$p_{n-2} \ w_{n-2}$

制約

$2 \leq N \leq 100000$

$0 \leq p_i \leq N-1$

$1 \leq w_i \leq 1000$

全て整数

全ての島と島の間が到達可能である

出力

答えを $1$ 行で出力せよ．

サンプル

各サンプルを図示すると次のようになる．

サンプル入力1

5
0 1
0 2
0 3
0 4

サンプル出力1

9

サンプル入力2

12
0 6
1 1
0 3
3 4
0 2
5 1
6 1
0 2
8 1
9 1
10 2

サンプル出力2

19

サンプル入力3

2
0 1

サンプル出力3

1

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable
import scala.io.StdIn._
object Main extends App {
  val n = readInt
  val longestPathToLeaf = Array.tabulate(n){_ ⇒ 0}
  val longestRootCircuitPath = Array.tabulate(n){ _ ⇒ 0}
  val longestRootCircuitEdge = Array.tabulate(n){ _ ⇒ 0}
  val longestEdge = Array.tabulate(n){_ ⇒ 0}
  val longestCircuit = Array.tabulate(n){_ ⇒ 0}
  val longestCircuitEdge = Array.tabulate(n){_ ⇒ 0}
  val node = Array.tabulate(n){_ ⇒ Nil: List[(Int, Int)]}
  val edgeCount = Array.tabulate(n){_ ⇒ 0}
  for (i ← 1 until n){
    val Array(p, w) = readLine.trim.split(' ').map(_.toInt)
    node(i) ::= (p, w)
    node(p) ::= (i, w)
    edgeCount(i) += 1
    edgeCount(p) += 1
  }
  var queue: mutable.Queue[Int] = mutable.Queue()
  edgeCount.indices.filter(i ⇒ edgeCount(i) == 1).foreach(queue.enqueue(_))
  while(queue.nonEmpty) {
    val current = queue.dequeue()
    edgeCount(current) -= 1
    for ((to, length) ← node(current) if edgeCount(to) != 0) {
      if (longestCircuitEdge(to) < math.max(length, longestEdge(current))) {
        longestCircuitEdge(to) = math.max(length, longestEdge(current))
      }
      if (longestCircuit(to) + longestCircuitEdge(to) < longestCircuit(current) + math.max(length, longestEdge(to))) {
        longestCircuitEdge(to) = math.max(length, longestEdge(to))
        longestCircuit(to) = longestCircuit(current)
      }
      if (longestCircuit(to) + longestCircuitEdge(to) < longestCircuit(current) + longestCircuitEdge(current)){
        longestCircuitEdge(to) = longestCircuitEdge(current)
        longestCircuit(to) = longestCircuit(current)
      }
      if (longestCircuit(to) + longestCircuitEdge(to) < longestPathToLeaf(to) + longestRootCircuitPath(current) + length + longestRootCircuitEdge(current)) {
        longestCircuitEdge(to) = longestRootCircuitEdge(current)
        longestCircuit(to) = longestPathToLeaf(to) + longestRootCircuitPath(current) + length
      }
      if (longestCircuit(to) + longestCircuitEdge(to) < longestRootCircuitPath(to) + longestPathToLeaf(current) + length + longestRootCircuitEdge(to)) {
        longestCircuitEdge(to) =  longestRootCircuitEdge(to)
        longestCircuit(to) = longestRootCircuitPath(to) + longestPathToLeaf(current) + length
      }
      if (longestRootCircuitPath(to) + longestRootCircuitEdge(to) < longestPathToLeaf(to) + math.max(length, longestEdge(current))) {
        longestRootCircuitPath(to) = longestPathToLeaf(to)
        longestRootCircuitEdge(to) = math.max(length, longestEdge(current))
      }
      if (longestRootCircuitPath(to) + longestRootCircuitEdge(to) < longestRootCircuitPath(current) + length + longestRootCircuitEdge(current)) {
        longestRootCircuitPath(to) = longestRootCircuitPath(current) + length
        longestRootCircuitEdge(to) = longestRootCircuitEdge(current)
      }
      if (longestRootCircuitPath(to) + longestRootCircuitEdge(to) < longestPathToLeaf(current) + length + longestEdge(to)) {
        longestRootCircuitPath(to) = longestPathToLeaf(current) + length
        longestRootCircuitEdge(to) = longestEdge(to)
      }
      if (longestEdge(to) < math.max(length, longestEdge(current))) {
        longestEdge(to) = math.max(length, longestEdge(current))
      }
      if (longestPathToLeaf(to) < longestPathToLeaf(current) + length) {
        longestPathToLeaf(to) = longestPathToLeaf(current) + length
      }
      edgeCount(to) -= 1
      if (edgeCount(to) == 1) {
        queue.enqueue(to)
      }
    }
  }
  println((0 until n).map{i ⇒ longestCircuit(i) + longestCircuitEdge(i)}.max)
}