#include <bits/stdc++.h>
using namespace std;
ofstream fout("heavypath.out");
//ifstream fin("heavypath.in");
const int NMax = 100010;
vector<int> G[NMax];
class Path {
public:
vector<int> P;
vector<int> T;
int parent;
Path() {
P.clear();
T.clear();
parent = 0;
}
void update(int node, int st, int dr, int pos, int val) {
if (st == dr) { T[node] = val; return; }
int mid = (st + dr) / 2;
if (pos <= mid) update(node * 2, st, mid, pos, val);
else update(node * 2 + 1, mid + 1, dr, pos, val);
T[node] = max(T[node * 2], T[node * 2 + 1]);
}
int maxim(int node, int st, int dr, int ql, int qr) {
if (st == ql && dr == qr) return T[node];
int mid = (st + dr) / 2;
int nr1 = 0, nr2 = 0;
if (ql <= mid) nr1 = maxim(node * 2, st, mid, ql, min(qr, mid));
if (qr > mid) nr2 = maxim(node * 2 + 1, mid + 1, dr, max(ql, mid + 1), qr);
return max(nr1, nr2);
}
void addToPath(int node) {
P.push_back(node);
}
};
class Node {
public:
int niv;
int sub;
int pos;
int val;
int path;
};
vector<Path> paths;
vector<Node> nodes(NMax);
void makePaths(int node, int prev, int level) {
int maxi = 0;
int connect = 0;
int subarb = 0;
nodes[node].niv = level;
for (int i = 0; i < G[node].size(); i++) {
int next = G[node][i];
if (next == prev) continue;
makePaths(next, node, level + 1);
if (nodes[next].sub > maxi) {
maxi = nodes[next].sub;
connect = next;
}
subarb += nodes[next].sub;
}
if (!maxi) {
Path aux;
aux.addToPath(node);
paths.push_back(aux);
nodes[node].path = paths.size() - 1;
nodes[node].sub = 1;
return;
}
paths[nodes[connect].path].addToPath(node);
nodes[node].path = nodes[connect].path;
nodes[node].sub = subarb + 1;
for (int i = 0; i < G[node].size(); i++) {
int next = G[node][i];
if (next == prev) continue;
if (next != connect) {
paths[nodes[next].path].parent = node;
}
}
}
void reversePathsAndMakeTrees() {
for (int i = 0; i < paths.size(); i++) {
reverse(paths[i].P.begin(), paths[i].P.end());
vector<int> aux = paths[i].P;
paths[i].T.resize(4 * aux.size() + 1);
for (int j = 0; j < aux.size(); j++) {
paths[i].update(1, 1, aux.size(), j + 1, nodes[aux[j]].val);
nodes[aux[j]].pos = j + 1;
}
}
}
void solve1(int node, int val) {
nodes[node].val = val;
paths[nodes[node].path].update(1, 1, paths[nodes[node].path].P.size(), nodes[node].pos, val);
}
int solve2(int x, int y) {
if (nodes[paths[nodes[x].path].P[0]].niv < nodes[paths[nodes[y].path].P[0]].niv) swap(x, y);
if (nodes[x].path == nodes[y].path) return paths[nodes[x].path].maxim(1, 1, paths[nodes[x].path].P.size(), min(nodes[x].pos, nodes[y].pos), max(nodes[x].pos, nodes[y].pos));
else return max(paths[nodes[x].path].maxim(1, 1, paths[nodes[x].path].P.size(), 1, nodes[x].pos), solve2(paths[nodes[x].path].parent, y));
}
void query(int m) {
int x, y, o;
for (int i = 1; i <= m; i++) {
//fin >> o >> x >> y;
scanf("%d%d%d", &o, &x, &y);
switch (o) {
case 0: solve1(x, y); break;
case 1: fout << solve2(x, y) << '\n'; break;
}
}
}
int main()
{
int n, m, x, y;
freopen("heavypath.in", "r", stdin);
//fin >> n >> m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &nodes[i].val);
for (int i = 1; i < n; i++) {
//fin >> x >> y;
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
makePaths(1, 0, 0);
reversePathsAndMakeTrees();
query(m);
return 0;
}