#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMax = 1e5 + 5;
vector < int > G[NMax], Paths[NMax];
int value[NMax], w[NMax], level[NMax];
int l[NMax], lDim[NMax], lFather[NMax], lLevel[NMax], lPos[NMax];
int aint[4 * NMax];
bool viz[NMax];
int pathNumber = 0;
void DFS(const int &node) {
viz[node] = true;
w[node] = 1;
int bestNext = -1;
bool leaf = true;
for(auto const &it: G[node]) {
if(viz[it] == false) {
level[it] = level[node] + 1;
DFS(it);
leaf = false;
if(bestNext == -1) {
bestNext = it;
} else {
if(w[it] > w[bestNext]) {
bestNext = it;
}
}
w[node] += w[it];
}
}
if(leaf == true) {
l[node] = ++pathNumber;
lDim[pathNumber] = 1;
Paths[pathNumber].push_back(node);
return;
}
l[node] = l[bestNext];
lDim[l[node]]++;
Paths[l[node]].push_back(node);
for(auto const &it: G[node]) {
if(it == bestNext || level[it] < level[node]) continue;
lFather[l[it]] = node;
lLevel[l[it]] = level[node];
}
}
void buildAINT(const int &node, const int &lo, const int &hi, const int &lError, const int &lant) {
if(lo == hi) {
aint[node + lError] = value[Paths[lant][lo - 1]];
return;
}
int mid = (lo + hi) >> 1;
buildAINT(node * 2, lo, mid, lError, lant);
buildAINT(node * 2 + 1, mid + 1, hi, lError, lant);
aint[node + lError] = max(aint[node * 2 + lError], aint[node * 2 + 1 + lError]);
}
inline void makePaths() {
level[1] = 1;
DFS(1);
for(int i = 1; i <= pathNumber; i++) {
reverse(Paths[i].begin(), Paths[i].end());
if(i > 1) lPos[i] = lPos[i - 1] + 4 * lDim[i - 1];
buildAINT(1, 1, lDim[i], lPos[i], i);
}
}
void Update(const int &node, const int &lo, const int &hi, const int &pos, const int &value, const int &lError) {
if(lo == hi) {
aint[node + lError] = value;
return;
}
int mid = (lo + hi) >> 1;
if(pos <= mid) {
Update(node * 2, lo, mid, pos, value, lError);
} else {
Update(node * 2 + 1, mid + 1, hi, pos, value, lError);
}
aint[node + lError] = max(aint[2 * node + lError], aint[2 * node + 1 + lError]);
}
int Query(const int &node, const int &lo, const int &hi, const int &a, const int &b, const int &lError) {
if(lo >= a && b >= hi) {
return aint[node + lError];
}
int mid = (lo + hi) >> 1;
int A, B;
A = B = 0;
if(a <= mid) A = Query(node * 2, lo, mid, a, b, lError);
if(mid < b) B = Query(node * 2 + 1, mid + 1, hi, a, b, lError);
return max(A, B);
}
int main() {
ios::sync_with_stdio(false);
int n, t;
fin >> n >> t;
for(int i = 1; i <= n; i++) fin >> value[i];
for(int i = 1; i < n; i++) {
int x, y;
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
makePaths();
while(t--) {
int type, x, y;
fin >> type >> x >> y;
if(type == 0) {
Update(1, 1, lDim[l[x]], level[x] - lLevel[l[x]], y, lPos[l[x]]);
} else {
int sol = 0;
while(true) {
if(l[x] == l[y]) {
if(level[x] > level[y]) swap(x, y);
sol = max(sol, Query(1, 1, lDim[l[x]], level[x] - lLevel[l[x]], level[y] - lLevel[l[x]], lPos[l[x]]));
break;
}
if(lLevel[l[x]] < lLevel[l[y]]) swap(x, y);
sol = max(sol, Query(1, 1, lDim[l[x]], 1, level[x] - lLevel[l[x]], lPos[l[x]]));
x = lFather[l[x]];
}
fout << sol << "\n";
}
}
return 0;
}