#include <bits/stdc++.h>
#define n_max 100000
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
int n, m, nr_lant, pos, qpoz, qval, start, finish, maxim;
int nivel[n_max + 5], t[n_max + 5], w[n_max + 5], heavy[n_max + 5], arb[4 * n_max + 5], lant[n_max + 5], poz[n_max + 5], val[n_max + 5];
vector<int> graf[n_max + 5];
void Read()
{
f>>n>>m;
for(int i = 1;i <= n;++i)
f>>val[i];
int x, y;
for(int i = 1;i < n;++i)
f>>x>>y, graf[x].push_back(y), graf[y].push_back(x);
}
void dfs(int nod, int parinte)
{
w[nod] = 1;
t[nod] = parinte;
nivel[nod] = nivel[parinte] + 1;
int maxim = 0;
for(auto it : graf[nod])
if(it != parinte)
{
dfs(it, nod);
w[nod] += w[it];
if(nivel[it] > maxim)
maxim = nivel[it], heavy[nod] = it; //doar in jos => iau subarborele cu cel mai mare numar de noduri
}
}
void build(int nod, int sus)
{
lant[nod] = sus, poz[nod] = ++pos; //lant <=> root
if(heavy[nod])
build(heavy[nod], sus); //si asa cele care nu sunt in heavy raman pe langa si o sa fie actualizate mai tarziu
for(auto it : graf[nod])
if(it != t[nod] && it != heavy[nod])
build(it, it); //cand ajung la un nod care e diferit de root, fac un nou lant, avand root-ul in nodul radacina al lantului
}
void update(int nod, int st, int dr)
{
if(qpoz < st || qpoz > dr)
return;
if(st == dr)
{
arb[nod] = qval;
return;
}
int mid = (st + dr) ;
update(2 * nod, st, mid);
update(2 * nod + 1, mid + 1, dr);
arb[nod] = max(arb[2 * nod], arb[2 * nod + 1]);
}
int query(int nod, int st, int dr)
{
if(finish < st || start > dr || st > dr)
return 0;
if(start <= st && dr <= finish)
return arb[nod];
int mid = (st + dr) / 2;
return max(query(2 * nod, st, mid), query(2 * nod + 1, mid + 1, dr));
}
int query_all(int x, int y)
{
int ans = 0;
while(lant[x] != lant[y])
{
if(nivel[lant[x]] > nivel[lant[y]]) // daca nivelul nodului "sef" este mai mare (adica este mai jos)
swap(x, y);
start = poz[lant[y]], finish = poz[y];
ans = max(ans, query(1, 1, n));
y = t[lant[y]];
}
if(nivel[x] > nivel[y])
swap(x, y);
start = poz[x]; finish = poz[y];
ans = max(ans, query(1, 1, n));
return ans;
}
void Solve()
{
dfs(1, 0);
build(1, 1);
for(int i = 1;i <= n;++i)
qval = val[i], qpoz = poz[i],update(1, 1, n);
int t, x, y;
for(int i = 1;i <= m;++i)
{
f>>t>>x>>y;
if(!t)
{
qval = y; qpoz = poz[x];
update(1, 1, n);
}
else
g<<query_all(x, y)<<'\n';
}
}
int main()
{
Read();
Solve();
return 0;
}