#include <fstream>
#include <algorithm>
#include <vector>
#define NM 100010
#define LM 17
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
int N, M, K;
int V[NM];
int WPath[NM], WPos[NM], Level[NM];
int PathSize[NM], PathFather[NM];
int Delay[NM], Size[NM];
vector<int> G[NM];
int AI[8*NM];
int L, R, P, val;
int Ancestors[LM][NM];
void Update (int node, int delay, int S, int D)
{
if (S>=D)
{
AI[node + delay]=val;
return;
}
int M=(S+D)/2;
if (P<=M)
Update(2*node, delay, S, M);
else
Update(2*node+1, delay, M+1, D);
AI[node + delay] = max( AI[2*node + delay], AI[2*node+1 + delay]);
}
void Query (int node, int delay, int S, int D)
{
if (L<=S && D<=R)
{
val=max(val, AI[node + delay]);
return;
}
int M=(S+D)/2;
if (L<=M)
Query(2*node, delay, S, M);
if (R>M)
Query(2*node+1, delay, M+1, D);
}
void Read ()
{
f >> N >> M;
for (int i=1; i<=N; i++)
f >> V[i];
for (int i=1; i<N; i++)
{
int a, b;
f >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
}
void DF (int node, int father)
{
int bigson=-1, bigsize=-1;
Size[node]=1;
Ancestors[0][node]=father;
Level[node]=1+Level[father];
for (vector<int>::iterator it=G[node].begin(); it!=G[node].end(); ++it)
{
if (*it==father)
continue;
DF(*it, node);
Size[node]+=Size[*it];
if (Size[*it]>bigsize)
{
bigsize=Size[*it];
bigson=*it;
}
}
if (bigson==-1)
{
++K;
WPath[node]=K;
WPos[node]=1;
PathSize[K]=1;
return;
}
WPath[node]=WPath[bigson];
PathSize[WPath[node]]++;
WPos[node]=PathSize[WPath[node]];
for (vector<int>::iterator it=G[node].begin(); it!=G[node].end(); ++it)
{
if (*it==father || *it==bigson)
continue;
PathFather[WPath[*it]]=node;
}
}
void BuildAncestors ()
{
for (int j=1; (1 << j)<N; j++)
for (int i=1; i<=N; i++)
Ancestors[j][i]= Ancestors[j-1][ Ancestors[j-1][i] ];
}
void ComputeDelay ()
{
for (int i=1; i<=K; i++)
Delay[i]=Delay[i-1] + 4*PathSize[i-1] + 1;
}
void Build ()
{
for (int i=1; i<=N; i++)
{
P=WPos[i];
val=V[i];
Update(1, Delay[WPath[i]], 1, PathSize[WPath[i]]);
}
}
int GetLCA (int a, int b)
{
int log1=0, log2=0;
if (Level[a]>Level[b])
swap(a, b);
for (log1=0; (1 << log1)<Level[a]; log1++);
for (log2=0; (1 << log2)<Level[b]; log2++);
for (int k=log2; k>=0; k--)
if (Ancestors[k][b]!=0 && (Level[b] - (1 << k)>=Level[a]))
b=Ancestors[k][b];
if (a==b)
return a;
for (int k=log1; k>=0; k--)
if (Ancestors[k][a]!=0 && Ancestors[k][a]!=Ancestors[k][b])
{
a=Ancestors[k][a];
b=Ancestors[k][b];
}
return Ancestors[0][a];
}
void GetANS (int x, int t)
{
while (WPath[x]!=WPath[t])
{
L=WPos[x];
R=PathSize[WPath[x]];
Query(1, Delay[WPath[x]], 1, PathSize[WPath[x]]);
x=PathFather[WPath[x]];
}
L=WPos[x];
R=WPos[t];
Query(1, Delay[WPath[x]], 1, PathSize[WPath[x]]);
}
void Solve ()
{
for (int i=1; i<=M; i++)
{
int t, x, y;
f >> t >> x >> y;
if (t==0)
{
P=WPos[x];
val=y;
Update(1, Delay[WPath[x]], 1, PathSize[WPath[x]]);
}
if (t==1)
{
int z=GetLCA(x, y);
val=0;
GetANS(x, z);
GetANS(y, z);
g << val << '\n';
}
}
}
int main ()
{
Read();
DF(1, 0);
BuildAncestors();
ComputeDelay();
Build();
Solve();
f.close();
g.close();
return 0;
}