#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
#define LeftSon (2 * Node)
#define RightSon (2 * Node + 1)
const int NMAX = 100010;
int N, M, X, Y, Type, NrChains, Ans, Level[NMAX], Weight[NMAX], Val[NMAX], Aint[4 * NMAX];
int Chain[NMAX], ChainDim[NMAX], ChainStart[NMAX], ChainFather[NMAX], ChainLevel[NMAX], ChainPos[NMAX];
bool Used[NMAX];
vector<int> G[NMAX], ChainNodes[NMAX];
void DFS(int Node, int Father)
{
Used[Node] = 1;
Level[Node] = Level[Father] + 1;
Weight[Node] = 1;
bool Leaf = 1;
int Heaviest = 0;
for(vector<int> :: iterator it = G[Node].begin(); it != G[Node].end(); ++ it)
if(!Used[*it])
{
Leaf = 0;
DFS(*it, Node);
Weight[Node] += Weight[*it];
if(Weight[*it] > Weight[Heaviest])
Heaviest = *it;
}
if(Leaf)
{
Chain[Node] = ++ NrChains;
ChainDim[NrChains] ++;
ChainNodes[NrChains].push_back(Node);
}else
{
Chain[Node] = Chain[Heaviest];
ChainDim[Chain[Node]] ++;
ChainNodes[Chain[Node]].push_back(Node);
for(vector<int> :: iterator it = G[Node].begin(); it != G[Node].end(); ++ it)
if(*it != Father && *it != Heaviest)
{
ChainLevel[Chain[*it]] = Level[Node];
ChainFather[Chain[*it]] = Node;
}
}
}
void Build(int Node, int Left, int Right, int Delay, int IndexChain)
{
if(Left >= Right)
{
Aint[Node + Delay] = Val[ ChainNodes[IndexChain][Left - 1] ];
return ;
}
int Mid = (Left + Right) / 2;
Build(LeftSon, Left, Mid, Delay, IndexChain);
Build(RightSon, Mid + 1, Right, Delay, IndexChain);
Aint[Node + Delay] = max(Aint[LeftSon + Delay], Aint[RightSon + Delay]);
}
void Path_Decomposition()
{
DFS(1, 0);
for(int i = 1; i <= NrChains; ++ i)
{
reverse(ChainNodes[i].begin(), ChainNodes[i].end());
for(int j = 0; j < ChainNodes[i].size(); ++ j)
ChainPos[ ChainNodes[i][j] ] = j + 1;
ChainStart[i] = ChainStart[i - 1] + 4 * ChainDim[i - 1];
Build(1, 1, ChainDim[i], ChainStart[i], i);
}
}
void Update(int Node, int Left, int Right, int Delay, int Pos, int Val)
{
if(Left == Right)
{
Aint[Node + Delay] = Val;
return ;
}
int Mid = (Left + Right) / 2;
if(Pos <= Mid) Update(LeftSon, Left, Mid, Delay, Pos, Val);
else Update(RightSon, Mid + 1, Right, Delay, Pos, Val);
Aint[Node + Delay] = max(Aint[LeftSon + Delay], Aint[RightSon + Delay]);
}
void Query(int Node, int Left, int Right, int Delay, int LeftBound, int RightBound)
{
if(LeftBound <= Left && Right <= RightBound)
{
Ans = max(Ans, Aint[Node + Delay]);
return ;
}
int Mid = (Left + Right) / 2;
if(LeftBound <= Mid) Query(LeftSon, Left, Mid, Delay, LeftBound, RightBound);
if(Mid < RightBound) Query(RightSon, Mid + 1, Right, Delay, LeftBound, RightBound);
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%i %i", &N, &M);
for(int i = 1; i <= N; ++ i) scanf("%i", &Val[i]);
for(int i = 1; i < N; ++ i)
{
scanf("%i %i", &X, &Y);
G[X].push_back(Y);
G[Y].push_back(X);
}
Path_Decomposition();
for(; M; M --)
{
scanf("%i %i %i", &Type, &X, &Y);
if(Type == 0) Update(1, 1, ChainDim[Chain[X]], ChainStart[Chain[X]], ChainPos[X], Y);
else
{
Ans = 0;
while(1)
{
if(Chain[X] == Chain[Y])
{
if(Level[X] >= Level[Y]) swap(X, Y);
Query(1, 1, ChainDim[Chain[X]], ChainStart[Chain[X]], ChainPos[X], ChainPos[Y]);
break;
}
if(ChainLevel[Chain[X]] < ChainLevel[Chain[Y]]) swap(X, Y);
Query(1, 1, ChainDim[Chain[X]], ChainStart[Chain[X]], 1, ChainPos[X]);
X = ChainFather[Chain[X]];
}
printf("%i\n", Ans);
}
}
}