#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#define NMax 100001
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
vector <int> v[NMax], lant[NMax], arbInt[NMax];
int w[NMax], label[NMax], pos[NMax], valori[NMax], roof[NMax], nivel[NMax], lantSize[NMax];
int n, m, x, y, op, labelNr = 1, posNr, VAL, R, POS, niv;
void DFS(int nod) {
int fiu;
w[nod] = 1;
niv++;
lant[labelNr].push_back(nod);
label[nod] = labelNr;
pos[nod] = posNr;
posNr++;
nivel[nod] = niv;
bool leaf = true;
int nodSize = v[nod].size();
for(int i = 0 ; i < nodSize; ++i) {
fiu = v[nod][i];
if(label[fiu])
continue;
DFS(fiu);
w[nod] += w[fiu];
roof[labelNr] = nod;
leaf = false;
posNr = 0;
}
if(leaf) {
lantSize[labelNr] = posNr;
labelNr++;
}
niv--;
}
void update(int nod, int st, int dr) {
if(st == dr) {
arbInt[R][nod] = VAL;
} else {
int mij = (st + dr) / 2;
if (POS <= mij) {
update(2 * nod, st, mij);
} else {
update(2 * nod + 1, mij + 1, dr);
}
if(valori[arbInt[R][2* nod]] > valori[arbInt[R][2 * nod+ 1]]) {
arbInt[R][nod] = arbInt[R][2 * nod];
} else {
arbInt[R][nod] = arbInt[R][2 * nod + 1];
}
}
}
void buildTree() {
int rSize = lantSize[R];
arbInt[R].resize(rSize * 4 + 1);
for(int i = 0; i < rSize; ++i) {
VAL = lant[R][i];
POS = i + 1;
update(1, 1, rSize);
}
}
int posStart, posFinish, arbLant, maximV;
void arbQuery(int nod, int st, int dr) {
if(st >= posStart && dr <= posFinish) {
maximV = max(maximV, valori[arbInt[arbLant][nod]]);
return;
}
int mid = (st + dr) / 2;
if(posStart <= mid) arbQuery(2 * nod, st, mid);
if(mid < posFinish) arbQuery(2 * nod + 1, mid + 1, dr);
}
int query(int x, int y) {
maximV = -1;
while(true) {
if(label[x] == label[y]) {
posStart = pos[x] + 1;
posFinish = pos[y] + 1;
if(posStart > posFinish) {
int aux = posFinish;
posFinish = posStart;
posStart = aux;
}
arbLant = label[x];
arbQuery(1, 1, lantSize[arbLant]);
break;
} else {
int dadX = roof[label[x]];
int dadY = roof[label[y]];
if(nivel[dadX] > nivel[dadY]) {
posStart = pos[1] + 1;
posFinish = pos[x] + 1;
arbLant = label[x];
arbQuery(1, 1, lantSize[arbLant]);
x = dadX;
} else {
posStart = pos[1] + 1;
posFinish = pos[y] + 1;
arbLant = label[y];
arbQuery(1, 1, lantSize[arbLant]);
y = dadY;
}
}
}
//cout<<'\n';
fout<<maximV<<'\n';
}
int main()
{
fin>>n>>m;
for(int i = 1; i <= n; ++i) {
fin>>valori[i];
}
for(int i = 1; i < n; ++i) {
fin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
DFS(1);
for(int i = 1 ; i <= labelNr; ++i) {
R = i;
buildTree();
}
for(int i = 1; i <= m; ++i) {
fin>>op>>x>>y;
if(op == 1) {
query(x, y);
} else {
valori[x] = y;
R = label[x];
VAL = lant[R][pos[x]];
POS = pos[x] + 1;
update(1, 1, lantSize[R]);
}
}
fin.close();
fout.close();
return 0;
}