#include <fstream>
#include <vector>
#include <algorithm>
#define Nmax 100005
#define INF 2000000000
#define pb push_back
using namespace std;
ofstream cout ("heavypath.out");
vector <int> Tree[Nmax],Paths[Nmax];
int Val[Nmax],Path[Nmax],Father[Nmax],Len[Nmax],Pos[Nmax],Lvl[Nmax],Nr[Nmax],aux,n;
class SegmTree
{
public:
vector <int> Aint;
inline void Update(int nod, int st, int dr, int p, int val)
{
if(st==dr)
{
Aint[nod]=val;
return;
}
int mij=((st+dr)>>1);
if(p<=mij) Update((nod<<1),st,mij,p,val);
else Update((nod<<1)+1,mij+1,dr,p,val);
Aint[nod]=max(Aint[(nod<<1)],Aint[(nod<<1)+1]);
}
inline int Query(int nod, int st, int dr, int x, int y)
{
if(st==x && y==dr) return Aint[nod];
int mij=((st+dr)>>1);
if(y<=mij) return Query((nod<<1),st,mij,x,y);
else
if(x>mij) return Query((nod<<1)+1,mij+1,dr,x,y);
return max(Query((nod<<1),st,mij,x,mij),Query((nod<<1)+1,mij+1,dr,mij+1,y));
}
private:
} STrees[Nmax];
inline void Dfs(int nod, int tata, int level)
{
Lvl[nod]=level;
int ok=0;
int node=0;
Nr[nod]=1;
for(auto it : Tree[nod])
{
if(it==tata) continue;
ok=1;
Dfs(it,nod,level+1);
Nr[nod]+=Nr[it];
if(Nr[it]>Nr[node]) node=it;
}
if(!ok)
{
Path[nod]=++aux;
Paths[aux].pb(nod);
return;
}
Path[nod]=Path[node]; Paths[Path[node]].pb(nod);
}
inline void Dfs1(int nod, int tata)
{
for(auto it : Tree[nod])
{
if(it==tata) continue;
Dfs1(it,nod);
if(Path[it]!=Path[nod]) Father[Path[it]]=nod;
}
}
inline void Init()
{
int i;
for(i=1;i<=aux;++i)
{
reverse(Paths[i].begin(),Paths[i].end());
int kkt=0;
for(auto it : Paths[i]) Pos[it]=++kkt;
Len[i]=Paths[i].size();
STrees[i].Aint.resize(3*Len[i]+10);
for(int j=0;j<STrees[i].Aint.size();++j) STrees[i].Aint[j]=0;
}
for(i=1;i<=n;++i)
STrees[Path[i]].Update(1,1,Len[Path[i]],Pos[i],Val[i]);
}
int main()
{
int i,x,y,t,sol,m;
ifstream cin ("heavypath.in");
cin>>n>>m;
for(i=1;i<=n;++i) cin>>Val[i];
for(i=1;i<n;++i)
{
cin>>x>>y;
Tree[x].pb(y);
Tree[y].pb(x);
}
Dfs(1,0,0);
Dfs1(1,0);
Init();
while(m--)
{
cin>>t>>x>>y;
if(!t) STrees[Path[x]].Update(1,1,Len[Path[x]],Pos[x],y);
else
{
int sol=-INF;
while(Path[x]!=Path[y])
{
if(Lvl[Father[Path[x]]]<Lvl[Father[Path[y]]]) swap(x,y);
sol=max(sol,STrees[Path[x]].Query(1,1,Len[Path[x]],1,Pos[x]));
x=Father[Path[x]];
}
int l1=min(Pos[x],Pos[y]),l2=max(Pos[x],Pos[y]);
sol=max(sol,STrees[Path[x]].Query(1,1,Len[Path[x]],l1,l2));
cout<<sol<<"\n";
}
}
return 0;
}