// cod naspa. treb sa i-o dau lu jean
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
#define Nmax 100010
int n, m;
int viz[Nmax], Nr[Nmax], Val[Nmax];
vector <int> V[Nmax];
vector <int> AI[Nmax];
int Cate[Nmax], Lant[Nmax], Poz[Nmax], Leg[Nmax], Tata[Nmax], Tlant[Nmax], Niv[Nmax], Bla[Nmax];
int Lca (int x, int y) {
while ( Lant[x] != Lant[y] ) {
if ( Niv[ Tlant[ Lant[x] ] ] > Niv[ Tlant[ Lant[y] ] ] ) x = Leg[ Lant[x] ];
else y = Leg[ Lant[y] ];
}
if (Niv[x] < Niv[y]) return x;
return y;
}
int VAL, POZ, A, B, REZ;
#define MIJ ((st + dr) >> 1)
#define N1 (nod << 1)
#define N2 ((nod << 1) + 1)
void updateAi (int lant, int nod, int st, int dr) {
if (st == dr) {
AI[lant][nod] = VAL;
return ;
}
if (POZ <= MIJ) updateAi (lant, N1, st, MIJ);
else updateAi (lant, N2, MIJ + 1, dr);
AI[lant][nod] = max ( AI[lant][N1], AI[lant][N2] );
}
void queryAi (int lant, int nod, int st, int dr) {
if (A <= st && dr <= B) {
REZ = max (REZ, AI[lant][nod]);
return ;
}
if (A <= MIJ) queryAi (lant, N1, st, MIJ);
if (MIJ < B) queryAi (lant, N2, MIJ + 1, dr);
}
void query (int x, int y) {
int aux;
if (Niv[x] < Niv[y]) {
aux = x;
x = y;
y = aux;
}
//printf ("-------\n");
for (;Lant[x] != Lant[y]; x = Leg[ Lant[x] ]) {
//printf ("%d %d\n", x ,y);
A = 1;
B = Poz[ x ];
if (A > B) {
aux = A;
A = B;
B = aux;
}
//printf ("%d %d %d\n", Lant[x], A, B);
queryAi (Lant[x], 1, 1, Cate[ Lant[x] ]);
}
//printf ("%d %d\n", x, y);
A = Poz[x];
B = Poz[y];
if (A > B) {
aux = A;
A = B;
B = aux;
}
//printf ("%d %d %d\n", Lant[x], A, B);
queryAi (Lant[x], 1, 1, Cate[ Lant[x] ]);
//printf ("-------\n");
}
void heavypath (int nod, int lant) {
viz[nod] = 1;
Lant[nod] = lant; Poz[nod] = ++Cate[lant];
if (Poz[nod] == 1) Tlant[lant] = nod;
for (vector <int>::iterator it = V[nod].begin (); it != V[nod].end (); it++)
if (viz[*it] == 0) {
if (Bla[nod] == 0) Bla[nod] = 1, heavypath (*it, lant);
else {
Cate[0]++;
Leg[ Cate[0] ] = nod;
heavypath (*it, Cate[0]);
}
}
}
void dfs (int nod, int niv) {
viz[nod] = 1; Nr[nod] = 1; Niv[nod] = niv;
for (vector <int>::iterator it = V[nod].begin (); it != V[nod].end (); it++)
if (viz[*it] == 0) {
dfs (*it, niv + 1);
Nr[nod]+= Nr[*it];
Tata[*it] = nod;
}
}
void readData () {
int i, x, y;
scanf ("%d %d", &n, &m);
for (i = 1; i <= n; i++)
scanf ("%d", &Val[i]);
for (i = 1; i < n; i++) {
scanf ("%d %d", &x, &y);
V[x].push_back (y);
V[y].push_back (x);
}
}
bool cmp (int a, int b) {
return Nr[a] > Nr[b];
}
int main () {
freopen ("heavypath.in", "r", stdin);
freopen ("heavypath.out", "w", stdout);
readData ();
dfs (1, 1);
int i, j;
memset (viz, 0, sizeof (viz));
for (i = 1; i <= n; i++)
sort (V[i].begin (), V[i].end (), cmp);
Cate[0] = 1;
heavypath (1, 1);
int len;
for (i = 1; i <= Cate[0]; i++) {
len = 4 * Cate[i];
for (j = 1; j <= len; j++)
AI[i].push_back (0);
}
for (i = 1; i <= n; i++) {
POZ = Poz[i];
VAL = Val[i];
updateAi (Lant[i], 1, 1, Cate[ Lant[i] ]);
}
int tip, x, y, lca;
for (i = 1; i <= m; i++) {
scanf ("%d", &tip);
if (tip == 0) {
scanf ("%d %d", &x, &y);
POZ = Poz[x];
VAL = y;
updateAi (Lant[x], 1, 1, Cate[ Lant[x] ]);
}
else {
scanf ("%d %d", &x, &y);
lca = Lca (x, y);
//printf ("%d %d %d\n", x, y, lca);
REZ = 0;
query (x, lca);
query (y, lca);
printf ("%d\n", REZ);
}
}
return 0;
}