#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int dim=100009;
vector<int>g[dim];///folosit doar la inceput
vector<int>v[dim];///pentru arborele final
////////////////////////////////////////////////////////////////////////pentru lca
int len;
vector<int> euler,aparitie,nivel;
void DFS(int x,int tata){
euler[++len]=x;
nivel[x]=nivel[tata]+1;
aparitie[x]=len;
for(int y:v[x]){
DFS(y,x);
euler[++len]=x;
}
}
struct SegmentTreeMinim{
struct Nod{
int val,poz;
}aint[4*dim];
Nod Merge(Nod n1,Nod n2){
if(n1.val<n2.val){
return n1;
}
return n2;
}
void update(int nod,int tl,int tr,int poz,Nod x){
if(tl==tr){
aint[nod].val=x.val;
aint[nod].poz=x.poz;
return;
}
int tm=(tl+tr)/2;
if(poz<=tm){
update(2*nod,tl,tm,poz,x);
}
else{
update(2*nod+1,tm+1,tr,poz,x);
}
aint[nod]=Merge(aint[2*nod],aint[2*nod+1]);
}
Nod query(int nod,int tl,int tr,int l,int r){
if(l==tl && r==tr){
return aint[nod];
}
int tm=(tl+tr)/2;
if(r<=tm){
return query(2*nod,tl,tm,l,r);
}
if(l>tm){
return query(2*nod+1,tm+1,tr,l,r);
}
return Merge(query(2*nod,tl,tm,l,tm),query(2*nod+1,tm+1,tr,tm+1,r));
}
}B;
void find_lca(){
DFS(1,0);
for(int i=1;i<=len;i++){
B.update(1,1,len,i,{nivel[euler[i]],euler[i]});
}
}
int lca(int a,int b){
a=aparitie[a];
b=aparitie[b];
if(a>b){
swap(a,b);
}
return B.query(1,1,len,a,b).poz;
}
////////////////////////////////////////////////////////////////////////
bool vizitat[dim];
vector<int>sz,parent;
void dfs_size(int x,int tata){
vizitat[x]=1;
sz[x]=1;
for(int y:g[x]){
if(!vizitat[y]){
dfs_size(y,x);
parent[y]=x;
v[x].push_back(y);
sz[x]+=sz[y];
}
}
g[x].clear();
}
struct SegmentTreeMaxim{
int aint[4*dim];
void update(int nod,int tl,int tr,int poz,int val){
if(tl==tr){
aint[nod]=val;
return;
}
int tm=(tl+tr)/2;
if(poz<=tm){
update(2*nod,tl,tm,poz,val);
}
else{
update(2*nod+1,tm+1,tr,poz,val);
}
aint[nod]=max(aint[2*nod],aint[2*nod+1]);
}
int query(int nod,int tl,int tr,int l,int r){
if(l==tl && r==tr){
return aint[nod];
}
int tm=(tl+tr)/2;
if(r<=tm){
return query(2*nod,tl,tm,l,r);
}
if(l>tm){
return query(2*nod+1,tm+1,tr,l,r);
}
return max(query(2*nod,tl,tm,l,tm),query(2*nod+1,tm+1,tr,tm+1,r));
}
}A;
int nr_comp;///nr total de componenete
vector<int>comp,val,poz_aint;
vector<int>c[dim];///nodurile care se afla in comp i
void HPD(int x,bool schimba,int comp_tata){///generare lanturi HPD
int comp_locala;
if(schimba){
nr_comp++;
comp_locala=nr_comp;
}
else{
comp_locala=comp_tata;
}
c[comp_locala].push_back(x);
comp[x]=comp_locala;
for(int y:v[x]){
if(sz[y]>sz[x]/2||v[x].size()==1){
HPD(y,0,comp_locala);
}
else{
HPD(y,1,comp_locala);
}
}
}
signed main(){
int n,q;
fin>>n>>q;
euler = vector<int>(2*n+9);
aparitie = vector<int>(2*n+9);
nivel = vector<int>(n+9);
comp = vector<int>(n+9);
val = vector<int>(n+9);
poz_aint = vector<int>(n+9);
sz = vector<int>(n+9);
parent = vector<int>(n+9);
for(int i=1;i<=n;i++){
fin>>val[i];
}
for(int i=2;i<=n;i++){
int x,y;
fin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs_size(1,0);
find_lca();
HPD(1,1,0);
int total=0;
for(int i=1;i<=nr_comp;i++){
for(int x:c[i]){
total++;
poz_aint[x]=total;
A.update(1,1,n,total,val[x]);
}
}
while(q--){
int op;
fin>>op;
if(op==0){
int poz,val;
fin>>poz>>val;
A.update(1,1,n,poz_aint[poz],val);
}
else{
int l,r;
fin>>l>>r;
int comun=lca(l,r);
int ans=0;
while(comp[l]!=comp[comun]){
ans=max(ans,A.query(1,1,n,poz_aint[c[comp[l]][0]],poz_aint[l]));
l=parent[c[comp[l]][0]];
}
ans=max(ans,A.query(1,1,n,poz_aint[comun],poz_aint[l]));
while(comp[r]!=comp[comun]){
ans=max(ans,A.query(1,1,n,poz_aint[c[comp[r]][0]],poz_aint[r]));
r=parent[c[comp[r]][0]];
}
ans=max(ans,A.query(1,1,n,poz_aint[comun],poz_aint[r]));
fout<<ans<<'\n';
}
}
}