#include <cstdio>
#include <vector>
#include <algorithm>
#define Nmax 100005
#define INF 2000000000
#define pb push_back
using namespace std;
int n,val[Nmax],NrPaths,Nr[Nmax],Path[Nmax],Pos[Nmax],Father[Nmax],Lvl[Nmax],Len[Nmax],values[Nmax];
vector <int> Tree[Nmax],Paths[Nmax];
class SegmentTree
{
public :
vector <int> aint;
inline void Build(int nod, int st, int dr)
{
if(st==dr)
{
aint[nod]=values[st];
return;
}
int mij=((st+dr)>>1);
Build(2*nod,st,mij);
Build(2*nod+1,mij+1,dr);
aint[nod]=max(aint[2*nod],aint[2*nod+1]);
}
inline void Update(int nod, int st, int dr, int x, int y)
{
if(st==dr)
{
aint[nod]=y;
return;
}
int mij=((st+dr)>>1);
if(x<=mij)
Update(2*nod,st,mij,x,y);
else
Update(2*nod+1,mij+1,dr,x,y);
aint[nod]=max(aint[2*nod],aint[2*nod+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(2*nod,st,mij,x,y);
else
if(x>mij)
return Query(2*nod+1,mij+1,dr,x,y);
else
return max(Query(2*nod,st,mij,x,mij),Query(2*nod+1,mij+1,dr,mij+1,y));
}
private :
};
SegmentTree STrees[Nmax];
inline void Dfs1(int nod, int tata, int level)
{
Nr[nod]=1; Lvl[nod]=level;
int node=0;
for(auto it : Tree[nod])
if(it!=tata)
{
Dfs1(it,nod,level+1);
Nr[nod]+=Nr[it];
if(Nr[it]>Nr[node]) node=it;
}
if(!node)
{
++NrPaths;
Paths[NrPaths].push_back(nod);
Path[nod]=NrPaths;
}
else
{
Path[nod]=Path[node];
Paths[Path[node]].push_back(nod);
}
}
inline void Dfs2(int nod, int tata)
{
for(auto it : Tree[nod])
{
if(it==tata) continue;
if(Path[it]!=Path[nod])
Father[Path[it]]=nod;
Dfs2(it,nod);
}
}
int main()
{
int i,x,y,Q,tip,sol;
freopen ("heavypath.in","r",stdin);
freopen ("heavypath.out","w",stdout);
scanf("%d%d", &n,&Q);
for(i=1;i<=n;++i) scanf("%d", &val[i]);
for(i=1;i<n;++i)
{
scanf("%d%d", &x,&y);
Tree[x].push_back(y);
Tree[y].push_back(x);
}
Dfs1(1,0,1);
for(i=1;i<=NrPaths;++i)
{
reverse(Paths[i].begin(),Paths[i].end());
int len=0;
for(int j=0;j<Paths[i].size();++j)
{
Pos[Paths[i][j]]=j+1;
values[++len]=val[Paths[i][j]];
}
STrees[i].aint.resize(3*len+5);
STrees[i].Build(1,1,len);
Len[i]=len;
Paths[i].clear();
}
Dfs2(1,0);
while(Q--)
{
scanf("%d%d%d", &tip,&x,&y);
if(!tip) STrees[Path[x]].Update(1,1,Len[Path[x]],Pos[x],y);
else
{
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));
printf("%d\n", sol);
}
}
return 0;
}