#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int NMAX = 100004;
struct SegmentTree
{
vector < int >aint;
vector < int >value;
int n;
SegmentTree()
{
aint.clear();
n = 0;
}
SegmentTree(const vector < int > _value)
{
n = _value.size();
value.resize(n+1);
for(int i=1;i<=n;++i)
value[i] = _value[i-1];
aint.resize(4*n);
Build(1,1,n);
}
inline void Build(const int node,const int Left,const int Right)
{
if(Left == Right)
{
aint[node] = value[Left];
return ;
}
int mid = (Left+Right)/2;
Build(2*node,Left,mid);
Build(2*node+1,mid+1,Right);
aint[node] = max(aint[2*node],aint[2*node+1]);
}
inline void Update(const int node,const int Left,const int Right,const int pos)
{
if(Left == Right)
{
aint[node] = value[Left];
return ;
}
int mid = (Left+Right)/2;
if(pos <= mid)
Update(2*node,Left,mid,pos);
else
Update(2*node+1,mid+1,Right,pos);
aint[node] = max(aint[2*node],aint[2*node+1]);
}
inline int Query(const int node,const int Left,const int Right,const int A,const int B)
{
if(A <= Left && Right <= B)
return aint[node];
int mid = (Left+Right)/2, x = 0, y = 0;
if(A <= mid)
x = Query(2*node,Left,mid,A,B);
if(mid < B)
y = Query(2*node+1,mid+1,Right,A,B);
return max(x,y);
}
inline void Update(const int pos,const int val)
{
value[pos] = val;
Update(1,1,n,pos);
}
};
vector < int > Tree[NMAX], values[NMAX];
int nrfii[NMAX], nrlanturi, nivel[NMAX], lant[NMAX], nodtata[NMAX];
int pozitielant[NMAX], value[NMAX], nrnoduri[NMAX];
inline void DFS(const int node,const int Father)
{
int fiumax = 0;
++nrfii[node];
for(auto x=Tree[node].begin(); x!=Tree[node].end();++x)
if(*x != Father)
{
nivel[*x] = nivel[node]+1;
DFS(*x,node);
nrfii[node] += nrfii[*x];
if(nrfii[*x] > nrfii[fiumax])
fiumax = *x;
}
if(fiumax == 0)
{
++nrlanturi;
nrnoduri[nrlanturi] = 1;
lant[node] = nrlanturi;
return ;
}
lant[node] = lant[fiumax];
++nrnoduri[lant[node]];
for(auto x=Tree[node].begin(); x!=Tree[node].end();++x)
if(*x != Father && *x != fiumax)
nodtata[lant[*x]] = node;
}
SegmentTree T[NMAX];
int main()
{
int n, m;
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
scanf("%d %d\n",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d ",&value[i]);
for(int i=1;i<n;++i)
{
int x, y;
scanf("%d %d\n",&x,&y);
Tree[x].push_back(y);
Tree[y].push_back(x);
}
nivel[1] = 1;
DFS(1,0);
for(int i=1;i<=nrlanturi;++i)
values[i].resize(nrnoduri[i]);
for(int i=1;i<=n;++i){
pozitielant[i] = nivel[i] - nivel[nodtata[lant[i]]];
values[lant[i]][pozitielant[i]-1] = value[i];
}
for(int i=1;i<=nrlanturi;++i)
T[i] = SegmentTree(values[i]);
while(m--)
{
int operation, x, y;
scanf("%d %d %d\n",&operation,&x,&y);
if(operation == 0)
T[lant[x]].Update(pozitielant[x],y);
else
{
int solution = 0;
while(lant[x]!=lant[y])
{
if(nivel[nodtata[lant[x]]] < nivel[nodtata[lant[y]]])
swap(x,y);
solution = max(solution,T[lant[x]].Query(1,1,nrnoduri[lant[x]],1,pozitielant[x]));
x = nodtata[lant[x]];
}
if(nivel[x] > nivel[y])
swap(x,y);
//printf("x=%d y=%d %d %d\n",x,y,pozitielant[x],pozitielant[y]);
solution = max(solution,T[lant[x]].Query(1,1,nrnoduri[lant[x]],pozitielant[x],pozitielant[y]));
printf("%d\n",solution);
}
}
return 0;
}