#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define MAX 100010
vector<int> Edge[MAX];
vector<int> Path[MAX];
bool Visited[MAX];
int N, M, Value[MAX], Height[MAX], Degree[MAX], Parent[MAX], pathHead[MAX], whatPath[MAX], posInPath[MAX], nrPaths;
void DFS(int X, int height) {
int Y = 0;
Visited[X] = true;
Height[X] = height;
for (int i = 0; i < Edge[X].size(); i++) {
if (!Visited[Edge[X][i]]) {
DFS(Edge[X][i], height + 1);
Parent[Edge[X][i]] = X;
Degree[X] += Degree[Edge[X][i]];
if (Degree[Edge[X][i]] > Degree[Y]) {
Y = Edge[X][i];
}
}
}
if (Degree[X] == 0) {
nrPaths++;
Path[nrPaths].push_back(X);
whatPath[X] = nrPaths;
} else {
whatPath[X] = whatPath[Y];
Path[whatPath[X]].push_back(X);
}
Degree[X]++;
}
void update(vector<int> &Tree, int Node, int L, int R, int position, int value) {
if (L == R) {
Tree[Node] = value;
} else {
int M = (L + R) / 2;
if (position <= M)
update(Tree, 2*Node, L, M, position, value);
else
update(Tree, 2*Node+1, M+1, R, position, value);
Tree[Node] = max(Tree[2*Node], Tree[2*Node+1]);
}
}
int query(vector<int> &Tree, int Node, int L, int R, int Lo, int Hi) {
if (Lo <= L && R <= Hi) {
return Tree[Node];
} else {
int Q, M = (L + R) / 2;
if (Lo <= M)
Q = query(Tree, 2*Node, L, M, Lo, Hi);
if (Hi > M)
Q = max(Q, query(Tree, 2*Node+1, M+1, R, Lo, Hi));
return Q;
}
}
int main() {
int X, O, Y;
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
scanf("%d %d", &N, &M);
for (int i = 1; i <= N; i++) {
scanf("%d", &Value[i]);
}
for (int i = 1; i < N; i++){
scanf("%d %d", &X, &Y);
Edge[X].push_back(Y);
Edge[Y].push_back(X);
}
DFS(1, 1);
for (int i = 1; i <= nrPaths; i++) {
X = Path[i].size();
reverse(Path[i].begin(), Path[i].end());
Path[i].resize(3 * X);
for (int j = X; j > 0; j--) {
Path[i][j] = Path[i][j-1];
posInPath[Path[i][j]] = j;
Parent[Path[i][j]] = Parent[Path[i][1]];
pathHead[Path[i][j]] = Path[i][1];
}
Path[i][0] = X;
}
for (int i = 1; i <= N; i++) {
update(Path[whatPath[i]], 1, 1, Path[whatPath[i]][0], posInPath[i], Value[i]);
}
while (M--) {
scanf("%d %d %d", &O, &X, &Y);
if (O == 0) {
update(Path[whatPath[X]], 1, 1, Path[whatPath[X]][0], posInPath[X], Y);
} else {
int Answer = 0;
while (whatPath[X] != whatPath[Y]) {
if (Height[pathHead[X]] > Height[pathHead[Y]]) {
Answer = max(Answer, query(Path[whatPath[X]], 1, 1, Path[whatPath[X]][0], 1, posInPath[X]));
X = Parent[pathHead[X]];
} else {
Answer = max(Answer, query(Path[whatPath[Y]], 1, 1, Path[whatPath[Y]][0], 1, posInPath[Y]));
Y = Parent[pathHead[Y]];
}
}
if (posInPath[X] > posInPath[Y]) swap(X, Y);
Answer = max(Answer, query(Path[whatPath[X]], 1, 1, Path[whatPath[X]][0], posInPath[X], posInPath[Y]));
printf("%d\n", Answer);
}
}
return 0;
}