#include <bits/stdc++.h>
using namespace std;
const int NMAX=1e5;
int n, q, val[NMAX+1];
vector<int> g[NMAX+1];
int depth[NMAX+1], sz[NMAX+1], par[NMAX+1], heavy[NMAX+1], head[NMAX+1], pos[NMAX+1];
int t[4*NMAX+4];
void segment_update(int v, int tl, int tr, int pos, int val)
{
if(tl==tr)
{
t[v]=val;
return;
}
int tm=(tl+tr)>>1;
if(pos<=tm)segment_update(2*v, tl, tm, pos, val);
else segment_update(2*v+1, tm+1, tr, pos, val);
t[v]=max(t[2*v], t[2*v+1]);
}
int segment_query(int v, int tl, int tr, int l, int r)
{
if(l>r)return 0;
if(tl==l && tr==r)return t[v];
int tm=(tl+tr)>>1;
return max(segment_query(2*v, tl, tm, l, min(r, tm)),
segment_query(2*v+1, tm+1, tr, max(l, tm+1), r));
}
void dfs(int nod, int p)
{
depth[nod]=depth[p]+1;
par[nod]=p;
sz[nod]=1;
int max_s=0;
for(auto &copil:g[nod])
if(copil!=p)
{
dfs(copil, nod);
sz[nod]+=sz[copil];
if(sz[copil]>max_s)
max_s=sz[copil], heavy[nod]=copil;
}
}
int tt;
void decompose(int nod, int h)
{
head[nod]=h;
pos[nod]=(++tt);
segment_update(1, 1, n, pos[nod], val[nod]);
if(heavy[nod])
decompose(heavy[nod], h);
for(auto &copil:g[nod])
if(copil!=par[nod] && copil!=heavy[nod])
decompose(copil, copil);
}
int query(int a, int b)
{
int maxim=0;
for(; head[a]!=head[b]; b=par[head[b]])
{
if(depth[head[a]] > depth[head[b]])swap(a, b);
maxim=max(maxim, segment_query(1, 1, n, pos[head[b]], pos[b]));
}
if(depth[a] > depth[b])swap(a, b);
maxim=max(maxim, segment_query(1, 1, n, pos[a], pos[b]));
return maxim;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
cin>>n>>q;
for(int i=1; i<=n; i++)
cin>>val[i];
for(int i=1, x, y; i<n; i++)
{
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1, 0);
decompose(1, 1);
while(q--)
{
int tip, x, y;
cin>>tip>>x>>y;
if(tip==0)
{
segment_update(1, 1, n, pos[x], y);
}
else
{
cout<<query(x, y)<<'\n';
}
}
return 0;
}