#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#define NMax 100001
#define pos(x, k) lant[k].size() - 1 - pos[x]
using namespace std;
/*
ifstream fin("grader_test20.in");
ofstream fout("grader_test20.out");
*/
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], father[NMax];
int n, m, x, y, op, labelNr = 1, posNr, VAL, R, POS, niv;
void DFS(int nod, int Tnod) {
int fiu, maxSon = 0;
w[nod] = 1;
nivel[nod] = nivel[Tnod] + 1;
int nodSize = v[nod].size();
bool leaf = true;
for(int i = 0; i < nodSize; i++) {
fiu = v[nod][i];
if(fiu == Tnod)
continue;
leaf = false;
father[fiu] = nod;
DFS(fiu, nod);
w[nod]+=w[fiu];
if(w[maxSon] < w[fiu]) {
maxSon = fiu;
}
}
if(leaf) {
lant[labelNr].push_back(0);
lant[labelNr].push_back(nod);
label[nod] = labelNr;
pos[nod] = 1;
labelNr++;
} else {
label[nod] = label[maxSon];
pos[nod] = pos[maxSon] + 1;
lant[label[nod]].push_back(nod);
}
}
/*
void DFS(int nod) {
int fiu;
w[nod] = 1;
niv++;
lant[labelNr].push_back(nod);
label[nod] = labelNr;
pos[nod] = posNr;
posNr++;
//if(posNr == 0)
// roof[labelNr] = nod;
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 = lant[R].size();
reverse(lant[R].begin() + 1, lant[R].end());
roof[R] = father[lant[R][1]];
/*
for(int j = 0; j <= rSize * 4; j++) {
arbInt[R].push_back(0);
}
*/
arbInt[R].resize(rSize * 4 + 1);
for(int i = 1; i < rSize; ++i) {
VAL = lant[R][i];
POS = i;
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];
posFinish = pos[y];
if(posStart > posFinish) {
int aux = posFinish;
posFinish = posStart;
posStart = aux;
}
arbLant = label[x];
arbQuery(1, 1, lant[arbLant].size());
break;
} else {
int dadX = roof[label[x]];
int dadY = roof[label[y]];
if(nivel[dadX] > nivel[dadY]) {
posStart = pos[1];
posFinish = pos[x];
arbLant = label[x];
//cout<<posStart<<' '<<posFinish<<' '<<arbLant<<'\n';
arbQuery(1, 1, lant[arbLant].size());
x = dadX;
} else {
posStart = pos[1];
posFinish = pos[y];
arbLant = label[y];
arbQuery(1, 1, lant[arbLant].size());
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, 0);
labelNr--;
for(int i = 1; i <= n; ++i) {
pos[i] = lant[label[i]].size() - pos[i];
cout<<pos[i]<<' ';
}
for(int i = 1; i <= labelNr; ++i) {
R = i;
buildTree();
}
/*
for(int i = 1; i <= labelNr; i++) {
for(int j = 1; j < lant[i].size(); j++) {
cout<<lant[i][j]<<' ';
}
cout<<'\n';
}
*/
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];
update(1, 1, lant[R].size());
}
}
fin.close();
fout.close();
return 0;
}