#include <bits/stdc++.h>
#define MAXN 100005
int N, Q;
int Parent[MAXN];
std::vector <int> ADC[MAXN];
inline void AddEdge(int X, int Y) {
ADC[X].push_back(Y);
ADC[Y].push_back(X);
}
int Ord[MAXN], NChains, C[MAXN], Rang[MAXN],
LVL[MAXN], V[MAXN];
std::vector <int> Chain[MAXN];
void DFS(int Vertex = 1, int Height = 1) {
LVL[Vertex] = Height;
bool bLeaf = true;
int Heavy = 0;
Rang[Vertex] = 1;
for (auto Edge:ADC[Vertex])
if (!LVL[Edge]) {
DFS(Edge, Height+1);
Parent[Edge] = Vertex;
bLeaf = false;
if (Rang[Edge] > Rang[Heavy])
Heavy = Edge;
Rang[Vertex] += Rang[Edge];
}
if (bLeaf)
C[Vertex] = ++NChains;
else C[Vertex] = C[Heavy];
Chain[C[Vertex]].push_back(Vertex);
}
std::vector <int> Tree[MAXN];
#define _Left 2*Index
#define _Right 2*Index+1
#define _Middle (Left+Right)/2
void Init(int treeidx, int Left, int Right, int Index = 1) {
if (Left == Right) {
Tree[treeidx][Index] = V[Chain[treeidx][Left]];
return;
}
Init (treeidx, Left, _Middle, _Left);
Init (treeidx, _Middle+1, Right, _Right);
Tree[treeidx][Index] = std::max(Tree[treeidx][_Left], Tree[treeidx][_Right]);
}
void BuildTrees() {
for (int i=1, j; i<=NChains; ++i) {
std::reverse(Chain[i].begin(), Chain[i].end());
for (j=0; j<Chain[i].size(); ++j)
Ord[Chain[i][j]] = j;
Tree[i].resize(4*Chain[i].size() + 5);
Init(i, 0, Chain[i].size()-1);
}
}
std::ifstream In ("heavypath.in");
std::ofstream Out("heavypath.out");
void Update(int treeidx, int Pos, int Left, int Right, int Index = 1) {
if (Left == Right) {
Tree[treeidx][Index] = V[Chain[treeidx][Left]];
return;
}
if (Pos <= _Middle) Update(treeidx, Pos, Left, _Middle, _Left);
else Update(treeidx, Pos, _Middle+1, Right, _Right);
Tree[treeidx][Index] = std::max(Tree[treeidx][_Left], Tree[treeidx][_Right]);
}
int Query(int treeidx, int A, int B, int Left, int Right, int Index = 1) {
if (A <= Left && Right <= B)
return Tree[treeidx][Index];
int Max = INT_MIN;
if (A <= _Middle) Max = Query(treeidx, A, B, Left, _Middle, _Left);
if (_Middle < B) Max = std::max(Max, Query(treeidx, A, B, _Middle+1, Right, _Right));
return Max;
}
int HPDQuery(int X, int Y) {
int Ans = INT_MIN;
int A, B;
while (C[X] != C[Y]) {
if (LVL[Chain[C[X]][0]] < LVL[Chain[C[Y]][0]])
std::swap (X, Y);
A = 0, B = Ord[X];
Ans = std::max(Ans, Query(C[X], A, B, 0, Chain[C[X]].size()-1));
X = Parent[Chain[C[X]][0]];
} return std::max(Ans, Query(C[X], std::min(Ord[X], Ord[Y]), std::max(Ord[X], Ord[Y]), 0, Chain[C[X]].size()-1));
}
void Citire() {
In >> N >> Q;
for (int i=1; i<=N; ++i)
In >> V[i], Parent[i] = i;
for (int i=1, X, Y; i<N; ++i)
In >> X >> Y, AddEdge(X, Y);
}
void Rezolvare() {
DFS();
BuildTrees();
for (int i=1, type, X, Y; i<=Q; ++i) {
In >> type >> X >> Y;
if (type) Out << HPDQuery(X, Y) << '\n';
else
V[X] = Y,
Update(C[X], Ord[X], 0, Chain[C[X]].size()-1);
}
}
int main()
{
Citire();
Rezolvare();
return 0;
}