#include <bits/stdc++.h>
#define n_max 100000
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
int n, m, pos;
int val[n_max + 5], heavy[n_max + 5], t[n_max + 5], nivel[n_max + 5], size[n_max + 5], lant[n_max + 5], poz[n_max + 5], arb[4 * 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)
{
size[nod] = 1;
nivel[nod] = nivel[parinte] + 1;
t[nod] = parinte;
int maxim = 0;
for(auto it : graf[nod])
if(it != parinte)
{
dfs(it, nod);
size[nod] += size[it];
if(maxim < size[it])
maxim = size[it], heavy[nod] = it;
}
}
void decompose(int nod, int sus)
{
lant[nod] = sus, poz[nod] = ++pos;
if(heavy[nod])
decompose(heavy[nod], sus);
for(auto it : graf[nod])
if(it != t[nod] && it != heavy[nod])
decompose(it, it);
}
void update(int nod, int st, int dr, int upos, int val)
{
if(upos < st || upos > dr)
return;
if(st == dr)
{
arb[nod] = val;
return;
}
int mid = (st + dr) / 2;
update(2 * nod, st, mid, upos, val);
update(2 * nod + 1, mid + 1, dr, upos, val);
arb[nod] = max(arb[2 * nod], arb[2 * nod + 1]);
}
int query(int nod, int st, int dr, int start, int finish)
{
if(start > dr || finish < st || st > dr)
return 0;
if(start <= st && dr <= finish)
return arb[nod];
int mid = (st + dr) / 2;
return max(query(2 * nod, st, mid, start, finish), query(2 * nod + 1, mid + 1, dr, start, finish));
}
int query_all(int x, int y)
{
int rez = 0;
while(lant[x] != lant[y])
{
if(nivel[lant[x]] < nivel[lant[y]])
swap(x, y);
rez = max(rez, query(1, 1, n, poz[lant[x]], poz[x]));
x = t[lant[x]];
}
if(nivel[x] < nivel[y])
swap(x, y);
rez = max(rez, query(1, 1, n, poz[y], poz[x]));
return rez;
}
void Solve()
{
dfs(1, 0);
decompose(1, 1);
for(int i = 1;i <= n;++i)
update(1, 1, n, poz[i], val[i]);
int t, x, y;
for(int i = 1;i <= m;++i)
{
f>>t>>x>>y;
if(!t)
update(1, 1, n, poz[x], y);
else
g<<query_all(x, y)<<'\n';
}
}
int main()
{
Read();
Solve();
return 0;
}