#include <bits/stdc++.h>
#define lll long long
#define pii pair<int,int>
#define pll pair<lll,lll>
#define fi first
#define se second
#define vi vector<int>
#define pb push_back
#define sz(a) (int)(a).size()
#define inf (INT_MAX/2-1)
#define infl (1LL<<61)
#define aaa system("pause");
#define dbg(x) cerr<<(#x)<<' '<<(x)<<'\n',aaa
#define dbga(x,n) cerr<<(#x)<<"[]: ";for(int _=0;_<=n;_++) cerr<<x[_]<<" ";cerr<<'\n'; aaa
#define maxn 100000
using namespace std;
ifstream fin ( "heavypath.in" );
ofstream fout ( "heavypath.out" );
struct nod
{
int val, chi, chp, szs, tata, niv;///chi=chain index, chp=chain poz, szs=marime subarbore
vi g;
};
struct lant { vi noduri, aint; };
nod v[maxn+5];
vector<lant> heavy;
bool viz[maxn+5];
void umax ( int &a, int b ) { a = max(a,b); }
void dfsh ( int from, int l )
{
v[from].niv = l;
viz[from] = 1;
for (int to: v[from].g)
if (!viz[to]) dfsh (to, l+1);
}
void dfs ( int from )
{
viz[from] = 1;
for (int to: v[from].g)
if (!viz[to]) v[to].tata = from, dfs (to);
v[from].szs = 1;
for (int to: v[from].g) v[from].szs += v[to].szs;
if (v[from].szs == 1)
{
heavy.pb(lant());
v[from].chi = sz(heavy) - 1;
v[from].chp = 0;
heavy[v[from].chi].noduri.pb(from);
}
else
{
int wh = v[from].g[0];///unde se adauga nodul
for (int to: v[from].g)
if (v[to].szs > v[wh].szs) wh = to;
v[from].chi = v[wh].chi;
v[from].chp = sz(heavy[v[from].chi].noduri);
heavy[v[from].chi].noduri.pb(from);
}
}
void update ( int from, int p, pii itv ) ///from = nod a carui val trb updatata
{
if (v[from].chp < itv.fi-1 || v[from].chp > itv.se-1) return;
if (itv.fi == itv.se) { heavy[v[from].chi].aint[p] = v[from].val; return; }
int mid = (itv.fi + itv.se) / 2;
update (from, p*2, {itv.fi, mid});
update (from, p*2+1, {mid+1, itv.se});
heavy[v[from].chi].aint[p] = max(heavy[v[from].chi].aint[p*2], heavy[v[from].chi].aint[p*2+1]);
}
void preupdate ( int from ) { update (from, 1, {1, sz(heavy[v[from].chi].noduri)}); }
int q_aint;
void query ( int index, int p, pii itv, pii ok )
{
if (ok.fi > itv.se || itv.fi > ok.se) return;
if (itv.fi >= ok.fi && itv.se <= ok.se) { umax(q_aint, heavy[index].aint[p]); return; }
int mid = (itv.fi + itv.se) / 2;
query (index, p*2, {itv.fi, mid}, ok);
query (index, p*2+1, {mid+1, itv.se}, ok);
}
int prequery ( int index, pii ok )
{
ok.fi++; ok.se++;
q_aint = 0;
query (index, 1, {1, sz(heavy[index].noduri)}, ok);
return q_aint;
}
int ind_dad_chain ( int from ) { return heavy[v[from].chi].noduri[sz(heavy[v[from].chi].noduri)-1]; }
int q_query;
void solve ( int x, int y )
{
if (v[x].chi == v[y].chi)
{
int _m = v[x].chp, _M = v[y].chp;
if (_m > _M) swap(_m, _M);
umax(q_query, prequery(v[x].chi, {_m, _M}));
return;
}
if (v[ind_dad_chain(x)].niv < v[ind_dad_chain(y)].niv) swap(x, y);
umax(q_query, prequery(v[x].chi, {v[x].chp, v[ind_dad_chain(x)].chp}));
solve(v[ind_dad_chain(x)].tata, y);
}
int main ()
{
int n, t; fin >> n >> t;
int i, a, b, op;
for (i = 0; i < n; i++) fin >> v[i].val;
for (i = 0; i < n-1; i++) fin >> a >> b, a--, b--, v[a].g.pb(b), v[b].g.pb(a);
dfsh (0,0); memset (viz, 0, sizeof viz);
dfs (0);
for (i = 0; i < sz(heavy); i++ ) heavy[i].aint.resize(4*sz(heavy[i].noduri)+5);
for (i = 0; i < n; i++ ) preupdate (i);
while (t--)
{
fin >> op >> a >> b;
if (op == 0)
{
a--;
v[a].val = b;
preupdate (a);
}
else
{
a--; b--; q_query = 0;
solve (a, b);
fout << q_query << '\n';
}
}
fin.close(); fout.close();
return 0;
}