#include <cstdio>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctype.h>
#include <cstring>
#include <ctime>
using namespace std;
#define MAXN 100005
int N, M, t, x, y;
int val[MAXN];
vector<int> A[MAXN];
int T[MAXN];
int lvl[MAXN];
int Aint[4 * MAXN];
bool viz[MAXN];
vector<int> lant[MAXN];
int nrLant;
int inLant[MAXN];
int pos[MAXN];
int szLant[MAXN];
int offset[MAXN];
int tataLant[MAXN];
pair<int, pair<int, int> > op[MAXN];
int dfs(int node, int prev) {
viz[node] = true;
T[node] = prev;
lvl[node] = lvl[prev] + 1;
int maxNrFii = 0;
int pmax = -1;
int nrFii = 0;
int crt;
for(vector<int> :: iterator it = A[node].begin(); it != A[node].end(); it++)
if(!viz[*it]) {
crt = dfs(*it, node);
nrFii += crt;
if(crt > maxNrFii) {
maxNrFii = crt;
pmax = *it;
}
}
if(maxNrFii == 0) {
inLant[node] = nrLant;
lant[nrLant].push_back(node);
szLant[nrLant] = 1;
nrLant++;
}
else {
int Lmax = inLant[pmax];
inLant[node] = Lmax;
lant[Lmax].push_back(node);
szLant[nrLant]++;
}
return nrFii;
}
void init(int k, int st, int dr, int off, int idxLant) {
if(st == dr) {
Aint[off + k] = val[lant[idxLant][st - 1]];
return;
}
int m = (st + dr) / 2;
init(2 * k, st, m, off, idxLant);
init(2 * k + 1, m + 1, dr, off, idxLant);
Aint[off + k] = max(Aint[off + 2 * k], Aint[off + 2 * k + 1]);
}
void update(int k, int st, int dr, int off, int qpos) {
if(st == dr) {
Aint[off + k] = y;
return;
}
int m = (st + dr) / 2;
if(qpos <= m)
update(2 * k, st, m, off, qpos);
else
update(2 * k + 1, m + 1, dr, off, qpos);
Aint[off + k] = max(Aint[off + 2 * k], Aint[off + 2 * k + 1]);
}
int query(int k, int st, int dr, int qst, int qdr, int off) {
if(qst <= st && dr <= qdr) {
return Aint[off + k];
}
int m = (st + dr) / 2;
int ret = 0;
if(qst <= m)
ret = max(ret, query(2 * k, st, m, qst, qdr, off));
if(qdr > m)
ret = max(ret, query(2 * k + 1, m + 1, dr, qst, qdr, off));
return ret;
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out","w", stdout);
scanf("%d %d", &N, &M);
for(int i = 1; i <= N; i++)
scanf("%d", &val[i]);
for(int i = 0; i < N - 1; i++) {
scanf("%d %d", &x, &y);
A[x].push_back(y);
A[y].push_back(x);
}
for(int i = 0; i < M; i++) {
scanf("%d %d %d", &t, &x, &y);
op[i] = make_pair(t, make_pair(x, y));
}
lvl[0] = 0;
dfs(1, 0);
offset[0] = 0;
for(int i = 0; i < nrLant; i++) {
if(i > 0)
offset[i] = offset[i - 1] + 4 * szLant[i - 1];
reverse(lant[i].begin(), lant[i].end());
init(1, 1, (int)lant[i].size(), offset[i], i);
for(vector<int> :: iterator it = lant[i].begin(); it != lant[i].end(); it++)
pos[*it] = (it - lant[i].begin()) + 1;
}
for(int i = 1; i <= N; i++)
tataLant[i] = T[lant[inLant[i]][0]];
for(int i = 0; i < M; i++) {
t = op[i].first;
x = op[i].second.first;
y = op[i].second.second;
if(t == 1) {
int ans = 0;
while(true) {
if(inLant[x] == inLant[y]) {
int left = min(pos[x], pos[y]);
int right = max(pos[x], pos[y]);
ans = max(ans, query(1, 1, lant[inLant[x]].size(), left, right, offset[inLant[x]]));
break;
}
if(lvl[tataLant[x]] < lvl[tataLant[y]])
swap(x, y);
ans = max(ans, query(1, 1, lant[inLant[x]].size(), 1, pos[x], offset[inLant[x]]));
x = tataLant[x];
}
printf("%d\n", ans);
}
else {
int crtL = inLant[x];
update(1, 1, lant[crtL].size(), offset[crtL], pos[x]);
}
}
return 0;
}