#include<cstdio>
#include<vector>
#include<algorithm>
#define MAXN 100010
using namespace std;
vector<int> g[MAXN],path[MAXN],arbint[MAXN];
int value[MAXN],which[MAXN],paths=0,weight[MAXN],depth[MAXN],position[MAXN],dad[MAXN];
int maxim(int a,int b){
if(a<b)
return b;
return a;
}
int minim(int a,int b){
if(a<b)
return a;
return b;
}
void decompose(int node,int up){
int dim=g[node].size(),i,where,maxim=-1;
weight[node]=1;
depth[node]=depth[up]+1;
if(dim==1&&node!=1){
paths++;
path[paths].push_back(-1);
path[paths].push_back(node);
which[node]=paths;
return;
}
for(i=0;i<dim;i++){
if(g[node][i]==up)
continue;
decompose(g[node][i],node);
weight[node]+=weight[g[node][i]];
if(weight[g[node][i]]>maxim){
maxim=weight[g[node][i]];
where=which[g[node][i]];
}
}
path[where].push_back(node);
which[node]=where;
for(i=0;i<dim;i++){
if(g[node][i]==up||which[g[node][i]]==where)
continue;
dad[which[g[node][i]]]=node;
}
}
bool cmp(int a,int b){
if(depth[a]<depth[b])
return true;
return false;
}
void initialize(int which_path,int left,int right){
int middle=(left+right)/2;
arbint[which_path].push_back(-1);
if(left==right)
return;
initialize(which_path,left,middle);
initialize(which_path,middle+1,right);
}
void build_arbint(int which_path,int node,int left,int right){
int middle=(left+right)/2;
arbint[which_path].push_back(-1);
if(left==right){
arbint[which_path][node]=value[path[which_path][left]];
return;
}
build_arbint(which_path,2*node,left,middle);
build_arbint(which_path,2*node+1,middle+1,right);
arbint[which_path][node]=maxim(arbint[which_path][2*node],arbint[which_path][2*node+1]);
}
void update(int which_path,int node,int left,int right,int index,int add){
int middle=(left+right)/2;
if(left==right){
arbint[which_path][node]=add;
return;
}
if(index<=middle)
update(which_path,2*node,left,middle,index,add);
else
update(which_path,2*node+1,middle+1,right,index,add);
arbint[which_path][node]=maxim(arbint[which_path][2*node],arbint[which_path][2*node+1]);
}
int query(int which_path,int node,int left,int right,int left_index,int right_index){
int middle=(left+right)/2,answer=-1;
if(left_index<=left&&right<=right_index)
return arbint[which_path][node];
if(left_index<=middle&&right_index>=left)
answer=maxim(answer,query(which_path,2*node,left,middle,left_index,right_index));
if(right_index>middle&&left_index<=right)
answer=maxim(answer,query(which_path,2*node+1,middle+1,right,left_index,right_index));
return answer;
}
int get_answer(int x,int y){
int temp;
if(which[x]==which[y])
return query(which[x],1,1,path[which[x]].size()-1,minim(position[x],position[y]),maxim(position[x],position[y]));
if(depth[dad[which[x]]]<depth[dad[which[y]]]){
temp=x;
x=y;
y=temp;
}
return maxim(query(which[x],1,1,path[which[x]].size()-1,1,position[x]),get_answer(dad[which[x]],y));
}
int main(){
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
int n,t,q,i,j,a,dim,b,x,y,op;
scanf("%d%d",&n,&t);
for(i=1;i<=n;i++)
scanf("%d",&value[i]);
for(i=1;i<n;i++){
scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
decompose(1,0);
for(i=1;i<=paths;i++){
sort(path[i].begin(),path[i].end(),cmp);
dim=path[i].size();
for(j=1;j<dim;j++)
position[path[i][j]]=j;
arbint[i].push_back(-1);
initialize(i,1,dim-1);
build_arbint(i,1,1,dim-1);
}
for(q=1;q<=t;q++){
scanf("%d%d%d\n",&op,&x,&y);
if(op==0){
value[x]=y;
update(which[x],1,1,path[which[x]].size()-1,x,y);
}
else
printf("%d\n",get_answer(x,y));
}
return 0;
}