Problem:
Dungeon 2

　

Bob is playing a game called "Dungeon 2" which is the sequel to the popular "Dungeon" released last year. The game is played on a map consisting of $N$ rooms and $N-1$ roads connecting them. The roads allow bidirectional traffic and the player can start his tour from any room and reach any other room by way of multiple of roads. A point is printed in each of the rooms.

Bob tries to accumulate the highest score by visiting the rooms by cleverly routing his character "Tora-Tora." He can add the point printed in a room to his score only when he reaches the room for the first time. He can also add the points on the starting and ending rooms of Tora-Tora’s journey. The score is reduced by one each time Tora-Tore passes a road. Tora-Tora can start from any room and end his journey in any room.

Given the map information, make a program to work out the maximum possible score Bob can gain.

Input

The input is given in the following format.

$N$
$p_1$
$p_2$
$...$
$p_N$
$s_1$ $t_1$
$s_2$ $t_2$
$...$
$s_{N-1}$ $t_{N-1}$

The first line provides the number of rooms $N$ ($1 \leq N \leq 100,000$). Each of the subsequent $N$ lines provides the point of the $i$-th room $p_i$ ($-100 \leq p_i \leq 100$) in integers. Each of the subsequent lines following these provides the information on the road directly connecting two rooms, where $s_i$ and $t_i$ ($1 \leq s_i < t_i \leq N$) represent the numbers of the two rooms connected by it. Not a single pair of rooms are connected by more than one road.

Output

Output the maximum possible score Bob can gain.

Sample Input 1

7
6
1
-1
4
3
3
1
1 2
2 3
3 4
3 5
5 6
5 7

Sample Output 1

10

For example, the score is maximized by routing the rooms in the following sequence: $6 \rightarrow 5 \rightarrow 3 \rightarrow 4 \rightarrow 3 \rightarrow 2 \rightarrow 1$.

Sample Input 2

4
5
0
1
1
1 2
2 3
2 4

Sample Output 2

5

The score is maximized if Tora-Tora stats his journey from room 1 and ends in the same room.

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable

object Main extends App {
  import scala.io.StdIn._
  val n = readLine.trim.toInt
  val nodes: Array[Node] = Array.tabulate(n){id ⇒ new Node(id, readLine.trim.toInt)}
  for (_ ← 1 until n){
    val Array(s, t) = readLine.trim.split(' ').map(_.toInt)
    nodes(s - 1).addEdge(nodes(t - 1))
    nodes(t - 1).addEdge(nodes(s - 1))
  }
  println(search(nodes(0)))
  //println(mergeAllTrees(nodes.map(node ⇒ new Tree(node))))
  def mergeAllTrees(trees: Array[Tree]): Long = {
    val current: mutable.Queue[Tree] = mutable.Queue[Tree](trees.filter(_.root.edges.size == 1):_*)
    for (_ ← 1 until trees.length){
      val top = current.dequeue()
      assert(top.root.edges.size == 1)
      val toIdx = top.root.edges.head.id
      trees(toIdx) = mergeTree(top, trees(toIdx))
      if (trees(toIdx).root.edges.size == 1) {
        current.enqueue(trees(toIdx))
      }
    }
    assert(trees.forall(_.root.edges.isEmpty))
    trees.map(_.maxScorePath).max
  }
  def max(elements: Long*): Long = elements.max
  def search(parent: Node): Long = {
    search(parent, new Node(0, 0)).maxPath
  }
  def search(current: Node, parent: Node): PathPattern = {
    var maxPath: Long = current.score
    var maxTrailIncludeRoot: Long = current.score
    var maxTrailEndWithRoot: Long = current.score
    var maxTour: Long = current.score
    for (next ← current.edges.filterNot(_ == parent)){
      val pattern = search(next, current)
      maxTrailIncludeRoot = max(maxTrailIncludeRoot, maxTrailEndWithRoot + pattern.maxTrailEndWithRoot - 1, maxTrailIncludeRoot + pattern.maxTour - 2, maxTour + pattern.maxTrailIncludeRoot - 2)
      maxTrailEndWithRoot = max(maxTrailEndWithRoot, maxTour + pattern.maxTrailEndWithRoot - 1, maxTrailEndWithRoot + pattern.maxTour - 2)
      maxTour = max(maxTour, maxTour + pattern.maxTour - 2)
      maxPath = max(maxPath, pattern.maxPath, maxTrailIncludeRoot)
    }
    PathPattern(maxPath, maxTrailIncludeRoot, maxTrailEndWithRoot, maxTour)
  }
  case class PathPattern(maxPath: Long, maxTrailIncludeRoot: Long, maxTrailEndWithRoot: Long, maxTour: Long)
  def mergeTree(from: Tree, to: Tree): Tree = {
    val maxTour: Long = List(to.maxScoreTour, to.maxScoreTour + from.maxScoreTour - 2).max
    val maxTrail: Long = List(to.maxScoreTrail, to.maxScoreTour + from.maxScoreTrail - 1, to.maxScoreTrail + from.maxScoreTour - 2).max
    val maxPath: Long = List(from.maxScoreTrail + to.maxScoreTrail - 1, from.maxScorePath, to.maxScorePath).max
    from.root.removeEdge(to.root)
    to.root.removeEdge(from.root)
    assert(maxPath >= maxTrail && maxTrail >= maxTour)
    new Tree(to.root, maxPath, maxTrail, maxTour)
  }
  class Tree(val root: Node, val maxScorePath: Long, val maxScoreTrail: Long, val maxScoreTour: Long) {
    def this(node: Node) {
      this(node, node.score, node.score, node.score)
    }
  }
  class Node(val id: Int, val score: Int) {
    private val edge: mutable.Set[Node] = mutable.Set[Node]()
    def addEdge(to: Node): Unit = edge.add(to)
    def removeEdge(to: Node): Unit = edge.remove(to)
    def edges: Iterable[Node] = edge
  }
  implicit class ScopedFunc[T](val value: T){
    def let[A](func: T ⇒ A): A = func(value)
    def also(func: T ⇒ Unit): T = {
      func(value)
      value
    }
  }
}
//http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3159975#3
//http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0389