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
