#include <bits/stdc++.h>
#define Nmax 100005
#define ls (((node+1)<<1)-1)
#define rs (ls+1)
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
int N,M,path_sz,tree_no,look_for,lsh,rsh;
int v[Nmax],weight[Nmax],lvl[Nmax],parent[Nmax],no_path[Nmax],pos[Nmax];
vector <int> tree[Nmax],Segment_Tree[Nmax],path[Nmax];
void read_data(){
f>>N>>M;
for(int i=1;i<=N;i++)
f>>v[i];
for(int x,y,i=1;i<N;i++){
f>>x>>y;
tree[x].push_back(y);
tree[y].push_back(x);
}
}
void build(int lo, int hi, int node){
if(lo==hi)
Segment_Tree[tree_no][node]=v[path[tree_no][lo]];
else{
int mid=(lo+hi)>>1;
build(lo,mid,ls);
build(mid+1,hi,rs);
Segment_Tree[tree_no][node]=max(Segment_Tree[tree_no][ls],Segment_Tree[tree_no][rs]);
}
}
void update(int lo, int hi, int node){
if(lo==hi)
Segment_Tree[tree_no][node]=v[path[tree_no][lo]];
else{
int mid=(lo+hi)>>1;
if(look_for<=mid)
update(lo,mid,ls);
else
update(mid+1,hi,rs);
Segment_Tree[tree_no][node]=max(Segment_Tree[tree_no][ls],Segment_Tree[tree_no][rs]);
}
}
int query(int lo, int hi, int node){
if(lsh<=lo and hi<=rsh)
return Segment_Tree[tree_no][node];
else{
int mid=(lo+hi)>>1,m1=INT_MIN,m2=INT_MIN;
if(lsh<=mid) m1=query(lo,mid,ls);
if(mid<rsh) m2=query(mid+1,hi,rs);
return max(m1,m2);
}
}
void DFS(int node){
int next_node=0;
weight[node]=1;
for(const auto &it:tree[node])
if(!lvl[it]){
lvl[it]=lvl[node]+1;
parent[it]=node;
DFS(it);
if(weight[it]>weight[next_node])
next_node=it;
weight[node]+=weight[it];
}
if(tree[node].size()==1 and parent[node]){
path[++path_sz].push_back(node);
no_path[node]=path_sz;
}
else{
path[no_path[next_node]].push_back(node);
no_path[node]=no_path[next_node];
}
}
void heavy_path_dec(){
lvl[1]=1;
DFS(1);
for(int i,k=1;k<=path_sz;k++){
reverse(path[k].begin(),path[k].end());
for(i=0;i<(int)path[k].size();i++)
pos[path[k][i]]=i;
Segment_Tree[k].resize(4*path[k].size());
tree_no=k;
build(0,path[k].size()-1,0);
}
}
int get_ans(int x, int y){
int ans=INT_MIN;
while(no_path[x]!=no_path[y]){
if(lvl[path[no_path[x]][0]]<lvl[path[no_path[y]][0]])
swap(x,y);
lsh=0;
rsh=pos[x];
tree_no=no_path[x];
ans=max(ans,query(0,path[tree_no].size()-1,0));
x=parent[path[tree_no][0]];
}
lsh=min(pos[x],pos[y]);
rsh=max(pos[x],pos[y]);
tree_no=no_path[x];
ans=max(ans,query(0,path[tree_no].size()-1,0));
return ans;
}
void solve_queries(){
int op,x,y;
while(M--){
f>>op>>x>>y;
if(!op){
v[x]=y;
tree_no=no_path[x];
look_for=pos[x];
update(0,path[tree_no].size()-1,0);
}
else g<<get_ans(x,y)<<'\n';
}
}
int main(){
read_data();
heavy_path_dec();
solve_queries();
return 0;
}