#include <bits/stdc++.h>
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
vector <int> graf[100001];
vector <int> Aint[100001];
vector <int> hpd[100001];
int nivel[100001];
int lanturi;
int where[100001];
int sub[100001];
int father[100001];
int poz[100001];
int val[100001];
void Build_Aint (int node, int st, int dr, int aint)
{
if (st == dr)
{
Aint[aint][node] = val[hpd[aint][st]];
return;
}
int mij = st+dr>>1;
Build_Aint(node<<1, st, mij, aint);
Build_Aint(node<<1|1, mij+1, dr, aint);
Aint[aint][node] = max(Aint[aint][node<<1], Aint[aint][node<<1|1]);
}
int Query (int node, int st, int dr, int a, int b, int aint)
{
if (a <= st && dr <= b)
return Aint[aint][node];
int mij = st+dr>>1;
int maxst = -1, maxdr = -1;
if (a <= mij) maxst = Query(node<<1, st, mij, a, b, aint);
if (mij < b) maxdr = Query(node<<1|1, mij+1, dr, a, b, aint);
return max(maxst, maxdr);
}
void Build_Hpd (int node, int tata)
{
father[node] = tata;
nivel[node] = nivel[tata]+1;
sub[node] = 1;
for (auto x:graf[node])
{
if (x == tata) continue;
// cout << "am muchia " << x << " " << node << "\n\n";
Build_Hpd(x, node);
sub[node]+=sub[x];
}
if (sub[node]==1)
{
++lanturi;
where[node] = lanturi;
poz[node] = 0;
hpd[lanturi].push_back (node);
return ;
}
int best = 0;
for (auto x:graf[node])
{
if (x == tata) continue;
if (sub[x] > sub[best])
best = x;
}
where[node] = where[best];
hpd[where[node]].push_back(node);
poz[node] = (int)hpd[where[node]].size()-1;
}
void reverse (int n)
{
for (int i = 1; i<=lanturi; ++i)
reverse(hpd[i].begin(), hpd[i].end());
for (int i = 1; i<=n; ++i)
poz[i] = (int)hpd[where[i]].size()-1-poz[i];
}
int solveMaxim (int x, int y)
{
int ans = -3;
int wx = where[x], wy = where[y];
if (wx == wy)
{
int a = min(poz[x], poz[y]), b = max(poz[x], poz[y]);
ans = max(ans, Query(1, 0, (int)hpd[wx].size()-1, a, b, wx));
}
else
{
if (nivel[hpd[wx][0]] < nivel[hpd[wy][0]])
{
swap(x, y);
swap (wx, wy);
}
ans = max (ans, Query(1, 0, (int)hpd[wx].size()-1, 0, poz[x], wx));
ans = max (ans, solveMaxim(father[hpd[wx][0]], y));
}
return ans;
}
void Update (int node, int st, int dr, int poz, int val, int aint)
{
// cout << "Updatez la lantul " << aint << " cu valoare " << val << " la poz " << poz << '\n';
// cout << st << " " << dr << '\n';
if (st == dr)
{
Aint[aint][node] = val;
return ;
}
int mij = st+dr>>1;
if (poz <= mij) Update(node<<1, st, mij, poz, val, aint);
else Update(node<<1|1, mij+1, dr, poz, val, aint);
Aint[aint][node] = max(Aint[aint][node<<1], Aint[aint][node<<1|1]);
}
int main(int argc, char const *argv[])
{
int n, m;
fin >> n >> m;
for (int i = 1; i<=n; ++i)
fin >> val[i];
for (int i = 1; i<n; ++i)
{
int x, y;
fin >> x >> y;
graf[x].push_back(y);
graf[y].push_back(x);
}
Build_Hpd(1, 0);
// for (int i = 1; i<=n; ++i) cout << where[i] << " ";
// return 0;
reverse(n);
// return 0;
for (int i = 1; i<=lanturi; ++i){
Aint[i].resize ((int)(hpd[i].size()) << 2);
Build_Aint(1, 0, (int)hpd[i].size()-1, i);
}
// return 0;
for (int i = 1; i<=m; ++i)
{
int type, x, y;
fin >> type >> x >> y;
if (type)
fout << solveMaxim(x, y) << '\n';
else
Update (1, 0, (int)hpd[where[x]].size()-1, poz[x], y, where[x]);
}
return 0;
}