#include <fstream>
#include <vector>
#include <algorithm>
const int LOG=17;
const int NMAX=100005;
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
vector <int> v[NMAX], path;
int val[NMAX], poz[NMAX], sz[NMAX], pth[NMAX], nd[NMAX];
int niv[NMAX], in[NMAX], out[NMAX], w[NMAX], hv[NMAX];
int dp[LOG+1][NMAX], aint[4*NMAX];
int n, q, nrp, cnt;
void build(int, int, int);
void update(int, int, int, int, int);
int query(int, int, int, int, int);
void build_lca();
void dfs1(int);
bool is_anc(int, int);
int lca(int, int);
void dfs2(int, int);
void decomp();
void ord();
int query_hpd(int, int);
void update_hpd(int, int);
int qrry(int, int);
bool cmp(int a, int b)
{
if(niv[a]==niv[b]) return a<b;
return niv[a]<niv[b];
}
int main()
{
int i, tip, a, b;
fin>>n>>q;
for(i=1; i<=n; i++) fin>>w[i];
for(i=1; i<n; i++)
{
fin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
dfs1(1);
build_lca();
dfs2(1, 1);
decomp();
ord();
for(i=1; i<=q; i++)
{
fin>>tip>>a>>b;
if(tip==0) update_hpd(a, b);
else fout<<query_hpd(a, b)<<'\n';
}
return 0;
}
void update_hpd(int nod, int val)
{
update(1, 1, n, poz[nod], val);
}
int query_hpd(int a, int b)
{
int maxim, lcaa;
lcaa=lca(a, b);
//fout<<a<<' '<<b<<' '<<lcaa<<'\n';
if(lcaa==a) return qrry(a, b);
if(lcaa==b) return qrry(b, a);
maxim=max(qrry(lcaa, a), qrry(lcaa, b));
return maxim;
}
int qrry(int a, int b)
{
int maxim=0;
while(true)
{
if(pth[a]==pth[b])
{
maxim=max(maxim, query(1, 1, n, poz[a], poz[b]));
break;
}
else maxim=max(maxim, query(1, 1, n, poz[path[pth[b]]], poz[b]));
b=dp[0][path[pth[b]]];
}
return maxim;
}
void ord()
{
int i, nr=0;
for(i=1; i<=n; i++) val[poz[i]]=w[i];
build(1, 1, n);
}
void decomp()
{
int nod, i, cnt=0;
path.push_back(0);
for(i=1; i<=n; i++) nd[i]=i;
sort(nd+1, nd+n+1, cmp);
for(i=1; i<=n; i++)
{
if(!pth[nd[i]])
{
++nrp;
nod=nd[i];
path.push_back(nod);
while(true)
{
//l-am adaugat in path-ul nrp
pth[nod]=nrp;
poz[nod]=++cnt;
if(hv[nod]==0) break;
nod=hv[nod];
}
}
}
}
void dfs2(int nod, int lvl)
{
sz[nod]=1;
niv[nod]=lvl;
for(auto i:v[nod])
{
if(!sz[i])
{
dfs2(i, lvl+1);
sz[nod]+=sz[i];
if(sz[hv[nod]]<sz[i]) hv[nod]=i;
}
}
v[nod].clear();
}
int lca(int a, int b)
{
int j;
if(a==b || is_anc(a, b)) return a;
if(is_anc(b, a)) return b;
for(j=LOG; j>=0; j--)
{
if(!is_anc(dp[j][a], b) && dp[j][a]!=0)
a=dp[j][a];
}
return dp[0][a];
}
bool is_anc(int a, int b)
{
return (in[a]<=in[b] && out[b]<=out[a]);
}
void dfs1(int nod)
{
in[nod]=++cnt;
for(auto i:v[nod])
{
if(!in[i])
{
dp[0][i]=nod;
dfs1(i);
}
}
out[nod]=++cnt;
}
void build_lca()
{
int i, j;
for(j=1; j<=LOG; j++)
{
for(i=1; i<=n; i++)
{
dp[j][i]=dp[j-1][dp[j-1][i]];
}
}
}
void build(int nod, int st, int dr)
{
if(st==dr)
{
aint[nod]=val[st];
return;
}
int mij=(st+dr)/2;
build(2*nod, st, mij);
build(2*nod+1, mij+1, dr);
aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}
void update(int nod, int st, int dr, int poz, int val)
{
if(st==dr)
{
aint[nod]=val;
return;
}
int mij=(st+dr)/2;
if(poz<=mij) update(2*nod, st, mij, poz, val);
else update(2*nod+1, mij+1, dr, poz, val);
aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}
int query(int nod, int st, int dr, int qst, int qdr)
{
if(st>=qst && dr<=qdr) return aint[nod];
int mij=(st+dr)/2, maxim=0;
if(qst<=mij) maxim=max(maxim, query(2*nod, st, mij, qst, qdr));
if(qdr>mij) maxim=max(maxim, query(2*nod+1, mij+1, dr, qst, qdr));
return maxim;
}