#include <fstream>
#include <vector>
#define mid (l+r)/2
using namespace std;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
const int NMAX=1e5+5, LMAX=17;
int n, m, val[NMAX], p[NMAX], d[NMAX], hc[NMAX];
int dtime, clc=1, poz[NMAX], lc[NMAX];
vector<int> adj[NMAX];
struct AINT
{
int aint[4*NMAX];
void update(int nod, int l, int r, int &poz, int &val)
{
if(poz<l || r<poz)
return;
if(l==r)
{
aint[nod]=val;
return;
}
update(2*nod, l, mid, poz, val);
update(2*nod+1, mid+1, r, poz, val);
aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}
int query(int nod, int l, int r, int &ql, int &qr)
{
if(qr<l || r<ql)
return 0;
if(ql<=l && r<=qr)
return aint[nod];
return max(query(2*nod, l, mid, ql, qr),
query(2*nod+1, mid+1, r, ql, qr));
}
}ds;
int DFS(int u)
{
int maxsz=0, szu=1, szv;
for(auto v:adj[u])
if(v!=p[u])
{
d[v]=d[u]+1; p[v]=u;
szv=DFS(v);
szu+=szv;
if(szv>maxsz)
{
maxsz=szv;
hc[u]=v;
}
}
return szu;
}
void DFSord(int u)
{
dtime++; poz[u]=dtime; lc[u]=clc;
ds.update(1, 1, n, dtime, val[u]);
if(hc[u]>0)
DFSord(hc[u]);
for(auto v:adj[u])
if(v!=p[u] && v!=hc[u])
{
clc=v;
DFSord(v);
}
}
int hvquery(int u, int v)
{
int ans=0;
while(lc[u]!=lc[v])
{
if(d[lc[u]]>d[lc[v]])
swap(u, v);
ans=max(ans, ds.query(1, 1, n, poz[lc[v]], poz[v]));
v=p[lc[v]];
}
if(d[u]>d[v])
swap(u, v);
ans=max(ans, ds.query(1, 1, n, poz[u], poz[v]));
return ans;
}
int main()
{
in>>n>>m;
for(int i=1;i<=n;i++)
in>>val[i];
for(int i=1;i<n;i++)
{
int a, b; in>>a>>b;
adj[a].push_back(b);
adj[b].push_back(a);
}
DFS(1);
DFSord(1);
while(m--)
{
int t, x, y;
in>>t>>x>>y;
if(t==0)
ds.update(1, 1, n, poz[x], y);
else
out<<hvquery(x, y)<<'\n';
}
return 0;
}