#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, V[NMAX], Type, X, Y, Aint[4 * NMAX], Level[NMAX];
int ChainLevel[NMAX], ChainIndex[NMAX], ChainDim[NMAX], ChainStart[NMAX], ChainPos[NMAX], ChainFather[NMAX], Weight[NMAX], NC;
vector<int> Chain[NMAX];
vector<int> G[NMAX];
bool Used[NMAX];
void DFS(int Node, int Father)
{
Used[Node] = 1;
Level[Node] = Level[Father] + 1;
bool Leaf = 1;
Weight[Node] = 1;
int Max = 0, Heaviest = 0;
for(vector<int> :: iterator it = G[Node].begin(); it != G[Node].end(); ++ it)
if(!Used[*it])
{
DFS(*it, Node);
Leaf = 0;
Weight[Node] += Weight[*it];
if(Weight[*it] > Max) Max = Weight[*it], Heaviest = *it;
}
if(Leaf == 1)
{
++ NC;
Chain[NC].push_back(Node);
ChainIndex[Node] = NC;
ChainDim[NC] ++;
}else
{
ChainIndex[Node] = ChainIndex[Heaviest];
ChainDim[ ChainIndex[Node] ] ++;
Chain[ ChainIndex[Node] ].push_back(Node);
for(vector<int> :: iterator it = G[Node].begin(); it != G[Node].end(); ++ it)
if(*it != Father && *it != Heaviest)
{
ChainFather[ ChainIndex[*it] ] = Node;
ChainLevel[ ChainIndex[*it] ] = Level[Node];
}
}
}
void Build(int Node, int Left, int Right, int Delay, int IndexChain)
{
if(Left == Right)
{
Aint[Node + Delay] = V[ Chain[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 PathDecomposition()
{
DFS(1, 0);
for(int i = 1; i <= NC; ++ i)
{
reverse(Chain[i].begin(), Chain[i].end());
ChainStart[i] = ChainStart[i - 1] + 4 * ChainDim[i - 1];
for(int j = 0; j < Chain[i].size(); ++ j)
ChainPos[ Chain[i][j] ] = j + 1;
Build(1, 1, ChainDim[i], ChainStart[i], i);
}
}
void Update(int Node, int Left, int Right, int Pos, int Val, int Delay)
{
if(Left == Right)
{
Aint[Node + Delay] = Val;
return ;
}
int Mid = (Left + Right) / 2;
if(Pos <= Mid) Update(LeftSon, Left, Mid, Pos, Val, Delay);
else Update(RightSon, Mid + 1, Right, Pos, Val, Delay);
Aint[Node + Delay] = max(Aint[LeftSon + Delay], Aint[RightSon + Delay]);
}
int Query(int Node, int Left, int Right, int LeftBound, int RightBound, int Delay)
{
if(LeftBound <= Left && Right <= RightBound) return Aint[Node + Delay];
int Mid = (Left + Right) / 2, Ans = 0;
if(LeftBound <= Mid) Ans = max(Ans, Query(LeftSon, Left, Mid, LeftBound, RightBound, Delay));
if(Mid < RightBound) Ans = max(Ans, Query(RightSon, Mid + 1, Right, LeftBound, RightBound, Delay));
return Ans;
}
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", &V[i]);
for(int i = 1; i < N; ++ i)
{
scanf("%i %i", &X, &Y);
G[X].push_back(Y);
G[Y].push_back(X);
}
PathDecomposition();
for(; M; M --)
{
scanf("%i %i %i", &Type, &X, &Y);
if(Type == 0) Update(1, 1, ChainDim[ ChainIndex[X] ], ChainPos[X], Y, ChainStart[ ChainIndex[X] ]);
else
{
int Ans = 0;
while(1)
{
if(ChainIndex[X] == ChainIndex[Y])
{
if(Level[X] >= Level[Y]) swap(X, Y);
Ans = max(Ans, Query(1, 1, ChainDim[ ChainIndex[X] ], ChainPos[X], ChainPos[Y], ChainStart[ChainIndex[X]]));
break;
}
if(ChainLevel[ChainIndex[X]] <= ChainLevel[ChainIndex[Y]]) swap(X, Y);
Ans = max(Ans, Query(1, 1, ChainDim[ ChainIndex[X] ], 1, ChainPos[X], ChainStart[ ChainIndex[X] ]));
X = ChainFather[ ChainIndex[X] ];
}
printf("%i\n", Ans);
}
}
}