#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMAX=100005;
int N, M, P[NMAX], top[NMAX], sz[NMAX], niv[NMAX], val[NMAX], ind[NMAX], seg[4*NMAX];
vector<int> g[NMAX];
void update(int nod, int st, int dr, int poz, int value){
if(st==dr){
seg[nod]=value;
return;
}
int mij=(st+dr)/2;
if(poz<=mij)
update(nod*2,st,mij,poz,value);
else
update(nod*2+1,mij+1,dr,poz,value);
seg[nod]=max(seg[nod*2],seg[nod*2+1]);
}
int query(int nod, int st, int dr, int p1, int p2){
if(p1<=st and p2>=dr)
return seg[nod];
if(st>p2 or dr<p1)
return 0;
int mij=(st+dr)/2;
return max(query(nod*2,st,mij,p1,p2),query(nod*2+1,mij+1,dr,p1,p2));
}
void dfsGetSize(int nod, int tata){
P[nod]=tata;
sz[nod]=1;
for(auto x: g[nod]){
if(x==tata)
continue;
niv[x]=niv[nod]+1;
dfsGetSize(x,nod);
sz[nod]+=sz[x];
}
}
int cnt=0;
void getDecomposition(int nod, int tata, int tp){
top[nod]=tp;
ind[nod]=++cnt;
update(1,1,N,ind[nod],val[nod]);
int size_max=-1, ind_max=-1;
for(auto x: g[nod]){
if(x==tata)
continue;
if(sz[x]>size_max){
size_max=sz[x];
ind_max=x;
}
}
if(ind_max==-1)
return;
getDecomposition(ind_max,nod,tp);
for(auto x: g[nod]){
if(x==tata or x==ind_max)
continue;
getDecomposition(x,nod,x);
}
}
int getSolution(int a, int b){
int sol=0;
while(top[a]!=top[b]){
if(niv[top[a]]<niv[top[b]])
swap(a,b);
sol=max(sol,query(1,1,N,ind[top[a]],ind[a]));
a=P[top[a]];
}
if(niv[a]>niv[b])
swap(a,b);
sol=max(sol,query(1,1,N,ind[a],ind[b]));
return sol;
}
int main()
{
fin>>N>>M;
for(int i=1;i<=N;i++)
fin>>val[i];
int a, b;
for(int i=1;i<N;i++){
fin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
dfsGetSize(1,0);
getDecomposition(1,0,1);
int tip;
while(M--){
fin>>tip>>a>>b;
if(tip==0){
update(1,1,N,ind[a],b);
val[a]=b;
}
else{
fout<<getSolution(a,b)<<'\n';
}
}
fin.close();
fout.close();
return 0;
}