#include <iostream>
#include <algorithm>
#include <vector>
using ll = long long;
using namespace std;
struct Point {
int value, depth = -1, number;
vector<int> neighbours;
};
vector<Point> points;
struct DSU {
vector<ll> wyniki; // remember to initialize
vector<int> parent;
DSU(int n) {
wyniki.resize(n, 0);
parent.resize(n);
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
int find(int x) {
if (parent[x] == x) return x;
return parent[x] = find(parent[x]);
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
cout << "alr connected?" << endl;
return;
}
if (points[y].value > points[x].value) {
swap(x, y);
}
parent[y] = x;
}
};
bool compare(int a, int b) {
return points[a].value < points[b].value;
}
// ===== LCA ADDITION START =====
const int LOG = 20;
vector<vector<int>> up;
void dfs_lca(int v, int p) {
up[v][0] = p;
for (int i = 1; i < LOG; i++) {
up[v][i] = up[up[v][i - 1]][i - 1];
}
for (int u : points[v].neighbours) {
if (u != p) {
dfs_lca(u, v);
}
}
}
void init_lca(int n) {
up.assign(n, vector<int>(LOG));
dfs_lca(0, 0);
}
int lca(int a, int b) {
// Lazy initialization since init_lca is not called in main
if (up.empty()) {
init_lca(points.size());
}
if (points[a].depth < points[b].depth) swap(a, b);
int diff = points[a].depth - points[b].depth;
for (int i = 0; i < LOG; i++) {
if (diff & (1 << i)) {
a = up[a][i];
}
}
if (a == b) return a;
for (int i = LOG - 1; i >= 0; i--) {
if (up[a][i] != up[b][i]) {
a = up[a][i];
b = up[b][i];
}
}
return up[a][0];
}
// ===== LCA ADDITION END =====
int dystans(int a, int b) {
return points[a].depth + points[b].depth - 2 * points[lca(a, b)].depth;
}
void DFS(int v);
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
DSU dsu(n);
points.resize(n);
for (int i = 0; i < n; i++) {
int v;
cin >> v;
points[i].value = v;
}
for (int i = 0; i < n - 1; i++) {
int a, b;
cin >> a >> b;
a--; b--;
points[a].neighbours.push_back(b);
points[b].neighbours.push_back(a);
}
points[0].depth = 0;
DFS(0);
vector<int> order(n);
for (int i = 0; i < n; i++) {
order[i] = i;
}
sort(order.begin(), order.end(), compare);
ll wynik = 0;
for (int i = 0; i < n; i++) {
//for each vertex
int p = order[i];
//cout << "I'm currently in point " << p << " and my value is " << points[p].value << endl;
//cout << "my neighbours are: \n";
for (int neighbour : points[p].neighbours) {
neighbour = dsu.find(neighbour);
//cout << neighbour << " ";
// nie robie & reference, wiec moge sie tak bawic
if (points[neighbour].value > points[p].value) {
//cout << "jego skipuje" << endl;
continue;
}
//cout << "obliczam wynik" << endl;
dsu.wyniki[p] = max(dsu.wyniki[p], dystans(p, neighbour) + dsu.wyniki[neighbour]);
//cout << "policzony wynik to " << dsu.wyniki[p] << endl;
dsu.unite(p, neighbour);
}
//cout << endl;
wynik = max(wynik, dsu.wyniki[p]);
}
cout << wynik << endl;
}
void DFS(int v) {
for (int neighour : points[v].neighbours) {
if (points[neighour].depth == -1) {
points[neighour].depth = points[v].depth + 1;
DFS(neighour);
}
}
}