#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 size=100000;
char buff[size+5];
int pos=size+1;
inline bool rable(char& c){
return ('0'<=c && c<='9');
}
int Read(int& x){
x=0;
while(!rable(buff[pos])){
pos++;
if(pos>=size) in.read(buff,size),pos=0;
}
while(rable(buff[pos])){
x=x*10 + int(buff[pos]) - '0';
pos++;
if(pos>=size) in.read(buff,size),pos=0;
}
}
const int Nmax = 100005;
int lg[2*Nmax+2];
vector<int> G[Nmax];
struct Query{
int t,x,y,lca;
} Q[Nmax];
int v[Nmax],Wchain[Nmax],Wpos[Nmax],Heavy[Nmax],T[Nmax],Sons[Nmax],Choice[Nmax],NumChains;
vector<int> LineChain[Nmax];
queue<int> q;
int E[2*Nmax],First[Nmax],Level[Nmax],mark[Nmax];
int N,M;
struct AI{
int Size,Rule;
int MinL(int& a,int& b){
if( Level[a] < Level[b] ) return a;
return b;
}
int MR(int a,int b){
if(Rule==0) return max(a,b);
if(Rule==1) return MinL(a,b);
}
vector<int> A;
AI(int size,int rule){
Size=size;
Rule=rule;
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]=MR(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 MR( 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,0); }
vector<AI> Chain;
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]++;
}
void GetLca(){
AI Lca=AI(E[0],1);
for(int i=1;i<=E[0];i++) Lca.update(i,E[i]);
for(int i=1;i<=M;i++){
if(Q[i].t==1){
int X=First[Q[i].x];
int Y=First[Q[i].y];
Q[i].lca = Lca.query(X,Y);
}
}
}
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;
Read(N);
Read(M);
for(int i=1;i<=N;i++) Read(v[i]);
for(int i=1;i<N;i++){
int x,y;
Read(x);
Read(y);
G[x].push_back(y);
G[y].push_back(x);
}
for(int i=1;i<=M;i++){
Read(Q[i].t);
Read(Q[i].x);
Read(Q[i].y);
}
Dfs(1,1);
GetLca();
BuildChains();
for(int i=1;i<=M;i++){
int t,x,y,lca;
t=Q[i].t;
x=Q[i].x;
y=Q[i].y;
lca=Q[i].lca;
if(t==0){
v[x]=y;
ChainUpdate(x);
}
if(t==1){
out<< max( QueryPath(lca,x) , QueryPath(lca,y) )<<'\n';
}
}
return 0;
}