#include<fstream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<queue>
#define abs(x) ((x>0)?(x):(-(x)))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define ll long long
using namespace std;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
const int Nmax = 100005;
int lg[2*Nmax+2];
struct AI{
int Size;
vector<int> A;
AI(int size){
Size=size;
A.insert (A.begin(),lg[size]*size+size,0);
}
void Update(int i,int st,int dr,int& w,int& val){
if(st>=dr) A[i]=val;
else{
int mij=(st+dr)/2;
if(w<=mij) Update(2*i,st,mij,w,val);
if(w>mij) Update(2*i+1,mij+1,dr,w,val);
A[i]=max(A[2*i],A[2*i+1]);
}
}
int Query(int i,int st,int dr,int a,int b){
if(a<=st && dr<=b) return A[i];
int mij=(st+dr)/2;
if(b<=mij) return Query(2*i,st,mij,a,b);
if(a>mij) return Query(2*i+1,mij+1,dr,a,b);
return max( Query(2*i,st,mij,a,mij) , Query(2*i+1,mij+1,dr,mij+1,b) );
}
void update(int wh,int val){
Update(1,1,Size,wh,val);
}
int query(int a,int b){
if(a>b) swap(a,b);
return Query(1,1,Size,a,b);
}
}; AI NewAI(int size){ return AI(size); }
vector<int> G[Nmax];
int v[Nmax],Wchain[Nmax],Wpos[Nmax],Heavy[Nmax],T[Nmax],Sons[Nmax],Choice[Nmax],NumChains;
vector<int> LineChain[Nmax];
queue<int> q;
vector<AI> Chain;
int E[2*Nmax],First[Nmax],Level[Nmax],mark[Nmax];
int N,M;
void Dfs(int x,int l){
mark[x]=1;
Level[x]=l;
E[++E[0]]=x;
First[x]=E[0];
for(vector<int>::iterator it=G[x].begin();it!=G[x].end();++it){
if(!mark[*it]){
T[*it]=x,Sons[x]++;
Dfs(*it,l+1);
E[++E[0]]=x;
Heavy[x]+=Heavy[*it];
}
}
Heavy[x]++;
}
int MinL(int a,int b){
if( Level[a] < Level[b] ) return a;
return b;
}
vector<int> rmq[20];
void BuildRMQ(){
Dfs(1,1);
rmq[0].insert(rmq[0].begin(),E[0]+30,0);
for(int i=1;i<=E[0];i++){
rmq[0][i]=E[i];
}
for(int i=1;i<=lg[E[0]];i++){
rmq[i].insert(rmq[i].begin(),E[0]-(1<<i)+30,0);
for(int j=1;j<=E[0]-(1<<i)+1;j++){
rmq[i][j]=MinL( rmq[i-1][j] , rmq[i-1][j+(1<<(i-1))] );
}
}
}
int Lca(int a,int b){
a=First[a];
b=First[b];
if(a>b) swap(a,b);
int dist=b-a;
int log=lg[dist];
int logs=(1<<log);
return MinL(rmq[log][a],rmq[log][a+dist-logs+1]);
}
void ChainUpdate(int x){
Chain[ Wchain[x] ].update( Wpos[x] , v[x] );
}
void BuildChains(){
for(int i=1;i<=N;i++){
if(!Sons[i]){
q.push(i);
Wchain[i]=++NumChains;
LineChain[NumChains].push_back(i);
}
}
while(!q.empty()){
int x=q.front(); q.pop();
if(!Wchain[x]){
Wchain[x]=Wchain[ Choice[x] ];
LineChain[ Wchain[x] ].push_back(x);
}
if(!Choice[ T[x] ] || Heavy[x] > Heavy[ Choice[ T[x] ] ]) Choice[ T[x] ]=x;
Sons[T[x]]--;
if(!Sons[T[x]]) q.push(T[x]);
}
Chain.push_back(NewAI(0));
for(int i=1;i<=NumChains;i++){
reverse( LineChain[i].begin() , LineChain[i].end() );
LineChain[i].insert(LineChain[i].begin(),0);
Chain.push_back(NewAI(LineChain[i].size()));
for(unsigned int j=1;j<LineChain[i].size();j++){
Wpos[ LineChain[i][j] ]=j;
ChainUpdate(LineChain[i][j]);
}
}
}
int QueryPath(int a,int b){
int m=0;
while( Wchain[a] != Wchain[b] ){
m=max( m , Chain[ Wchain[b] ].query(1,Wpos[b]) );
b=T[ LineChain[Wchain[b]][1] ];
}
m=max( m , Chain[ Wchain[a] ].query(Wpos[a],Wpos[b]) );
return m;
}
int main(){
for(int i=2;i<=2*Nmax;i++) lg[i]=lg[i>>1]+1;
in>>N>>M;
for(int i=1;i<=N;i++) in>>v[i];
for(int i=1;i<N;i++){
int x,y;
in>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
BuildRMQ();
BuildChains();
for(int i=1;i<=M;i++){
int t,x,y;
in>>t>>x>>y;
if(t==0){
v[x]=y;
ChainUpdate(x);
}
if(t==1){
int lca=Lca(x,y);
out<< max( QueryPath(lca,x) , QueryPath(lca,y) )<<'\n';
}
}
return 0;
}