#include <cstdio>
#include <vector>
#include <algorithm>
const int MAX_N(100005);
int n, m, Chains;
std::vector<int> Graph [MAX_N];
int Value [MAX_N];
std::vector<int> Chain [MAX_N];
int ChainIndex [MAX_N];
int ChainParent [MAX_N];
int Position [MAX_N];
int ItIndex [MAX_N];
int It [MAX_N << 2];
int Level [MAX_N];
int Weight [MAX_N];
inline void Read (void)
{
std::scanf("%d %d",&n,&m);
int i;
for (i = 1 ; i <= n ; ++i)
std::scanf("%d",&Value[i]);
int a, b;
for (i = 1 ; i < n ; ++i)
{
std::scanf("%d %d",&a,&b);
Graph[a].push_back(b);
Graph[b].push_back(a);
}
}
void DepthFirstSearch (int parent, int node, int level)
{
Level[node] = level;
if (Graph[node].size() == 1 && node != 1)
{
++Chains;
ChainIndex[node] = Chains;
Chain[Chains].push_back(node);
ChainParent[Chains] = parent;
Weight[node] = 1;
return;
}
int optimal(0), weight(0);
for (auto it : Graph[node])
if (it != parent)
{
DepthFirstSearch(node,it,level + 1);
if (weight < Weight[it])
{
optimal = ChainIndex[it];
weight = Weight[it];
}
Weight[node] += Weight[it];
}
++Weight[node];
Chain[optimal].push_back(node);
ChainIndex[node] = optimal;
ChainParent[optimal] = parent;
for (auto it : Graph[node])
if (it != parent && ChainIndex[it] != optimal)
ChainParent[ChainIndex[it]] = node;
}
inline void HeavyPathDecomposition (void)
{
DepthFirstSearch(1,1,1);
int i, j;
for (i = 1 ; i <= Chains ; ++i)
{
std::reverse(Chain[i].begin(),Chain[i].end());
for (j = 0 ; j < Chain[i].size() ; ++j)
Position[Chain[i][j]] = j;
ItIndex[i] = ItIndex[i - 1] + (Chain[i - 1].size() << 2);
}
}
inline int Left_son (const int INDEX)
{
return (INDEX << 1) + 1;
}
inline int Right_son (const int INDEX)
{
return (INDEX << 1) + 2;
}
inline int Max (const int A, const int B)
{
return (Value[A] > Value[B] ? A : B);
}
void ItBuild (int index, int left, int right, int chain)
{
if (left == right)
{
It[index + ItIndex[chain]] = Chain[chain][left];
return;
}
int mid((left + right) >> 1);
ItBuild(Left_son(index),left,mid,chain);
ItBuild(Right_son(index),mid + 1,right,chain);
It[index + ItIndex[chain]] = Max(It[Left_son(index) + ItIndex[chain]],It[Right_son(index) + ItIndex[chain]]);
}
inline void Build (void)
{
for (int i(1) ; i <= Chains ; ++i)
ItBuild(0,0,Chain[i].size() - 1,i);
}
void ItUpdate (int index, int left, int right, int pos, int jump)
{
if (left == right)
return;
int mid((left + right) >> 1);
if (pos <= mid)
ItUpdate(Left_son(index),left,mid,pos,jump);
else
ItUpdate(Right_son(index),mid + 1,right,pos,jump);
It[index + jump] = Max(It[Left_son(index) + jump],It[Right_son(index) + jump]);
}
inline void Update (int x, int y)
{
Value[x] = y;
ItUpdate(0,0,Chain[ChainIndex[x]].size() - 1,Position[x],ItIndex[ChainIndex[x]]);
}
int ItQuery (int index, int left, int right, int ql, int qr, int jump)
{
if (ql <= left && right <= qr)
return It[index + jump];
int mid((left + right) >> 1), max(0);
if (ql <= mid)
max = ItQuery(Left_son(index),left,mid,ql,qr,jump);
if (qr > mid)
max = Max(max,ItQuery(Right_son(index),mid + 1,right,ql,qr,jump));
return max;
}
inline int Query (int x, int y)
{
int result(0);
while (true)
{
if (ChainIndex[x] == ChainIndex[y])
{
if (Position[x] > Position[y])
std::swap(x,y);
result = Max(result,ItQuery(0,0,Chain[ChainIndex[x]].size() - 1,Position[x],Position[y],ItIndex[ChainIndex[x]]));
break;
}
if (Level[ChainParent[ChainIndex[x]]] < Level[ChainParent[ChainIndex[y]]])
std::swap(x,y);
result = Max(result,ItQuery(0,0,Chain[ChainIndex[x]].size() - 1,0,Position[x],ItIndex[ChainIndex[x]]));
x = ChainParent[ChainIndex[x]];
}
return result;
}
int main (void)
{
std::freopen("heavypath.in","r",stdin);
std::freopen("heavypath.out","w",stdout);
Read();
HeavyPathDecomposition();
Build();
int t, x, y;
while (m)
{
std::scanf("%d %d %d",&t,&x,&y);
if (t == 0)
Update(x,y);
else if (t == 1)
std::printf("%d\n",Value[Query(x,y)]);
--m;
}
std::fclose(stdin);
std::fclose(stdout);
return 0;
}