#include <iostream>
#include <fstream>
#include <vector>
#define NMAX 100000 //o suta de mii
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
int N, M;
int REZ;
int nrLanturi;
int tt[NMAX + 1];
int val[NMAX + 1];
vector <int> v[NMAX + 1];
int lant[NMAX + 1];
int posLant[NMAX + 1];
int tataLant[NMAX + 1];
int dimensiuneLant[NMAX + 1];
int depth[NMAX + 1];
int **tree;
void citire(){
fin >> N >> M;
for(int i = 1; i <= N; i++){
fin >> val[i];
}
for(int i = 1; i <= N - 1; i++){
int x, y;
fin >> x >> y;
v[x].push_back(y);
v[y].push_back(x);
}
}
int DFSfirst(int node, int tata){
int smNode = 1;
tt[node] = tata;
depth[node] = depth[tata] + 1;
int MX = -1;
int vecMx;
for(int i = 0; i < v[node].size(); i++){
int vec = v[node][i];
if(vec != tata){
int smVec = DFSfirst(vec, node);
if(smVec > MX){
MX = smVec;
vecMx = vec;
}
smNode += smVec;
}
}
if(MX == -1){
//frunza
nrLanturi++;
lant[node] = nrLanturi;
dimensiuneLant[nrLanturi] = 1;
tataLant[nrLanturi] = node;
}
else {
lant[node] = lant[vecMx];
dimensiuneLant[ lant[node] ]++;
tataLant[ lant[node] ] = node;
}
return smNode;
}
void DFSsecond(int node, int tata){
if(lant[node] != lant[tata]){
posLant[node] = 1;
}
else {
posLant[node] = posLant[tata] + 1;
}
for(int i = 0; i < v[node].size(); i++){
int vec = v[node][i];
if(vec != tata){
DFSsecond(vec, node);
}
}
}
int queryTree(int tree[], int node, int left, int right, int A, int B){
if(A <= left && right <= B){
return tree[node];
}
int mid = left + (right - left) / 2;
int rez1 = -1, rez2 = -1;
if(A <= mid){
rez1 = queryTree(tree, node * 2, left, mid, A, B);
}
if(B >= mid + 1){
rez2 = queryTree(tree, node * 2 + 1, mid + 1, right, A, B);
}
return max(rez1, rez2);
}
void updateTree(int tree[], int node, int left, int right, int pos, int val){
if(left == right){
tree[node] = val;
return;
}
int mid = left + (right - left) / 2;
if(pos <= mid){
updateTree(tree, node * 2, left, mid, pos, val);
}
else {
updateTree(tree, node * 2 + 1, mid + 1, right, pos, val);
}
tree[node] = max(tree[node * 2], tree[node * 2 + 1]);
}
void urcareLant(int &node){
int NR = lant[node];
int nd = 1;
int left = 1;
int right = dimensiuneLant[NR];
int A = 1;
int B = posLant[node];
REZ = max(REZ, queryTree(tree[NR], nd, left, right, A, B));
//printf("node = tt[ tataLant[ lant[%d] ] ] = tt[ tataLant[%d] ] = tt[%d] = %d\n", node, lant[node], tataLant[ lant[node] ], tt [ tataLant[ lant[node] ] ]);
node = tt [ tataLant[ lant[node] ] ];
}
inline int comparareLant(int X, int Y){
//returneaza 1 daca X e mai sus, 0 daca Y e mai sus
return depth[ tataLant[ lant[X] ] ] < depth[ tataLant[ lant[Y] ] ];
}
int query(int X, int Y){
//X mereu trebuie sa fie in lantul mai de sus
REZ = -1;
if( !comparareLant(X, Y) ){ //adica daca lantul lui Y este mai sus decat lantul lui X
swap(X, Y);
}
while(lant[X] != lant[Y]){
//printf("(X, Y) = (%d, %d)\n", X, Y);
//printf("Urc pe lant %d\n", Y);
urcareLant(Y);
//printf("Am urcat pe lant %d\n", Y);
if( !comparareLant(X, Y) ){
swap(X, Y);
}
}
if(posLant[X] > posLant[Y]){
swap(X, Y);
}
REZ = max(REZ, queryTree(tree[ lant[X] ], 1, 1, dimensiuneLant[ lant[X] ], posLant[X], posLant[Y]));
//printf("\n\n");
return REZ;
}
inline void buildTree(){
//aloc memorie
tree = (int **) malloc( (nrLanturi + 1) * sizeof(int *) );
for(int i = 1; i <= nrLanturi; i++){
tree[i] = (int *) malloc( (4 * dimensiuneLant[i] + 1) * sizeof(int) );
}
//fac build propriu-zis
for(int i = 1; i <= N; i++){
updateTree(tree[ lant[i] ], 1, 1, dimensiuneLant[ lant[i] ], posLant[i], val[i]);
}
}
int main()
{
citire();
DFSfirst(1, 1);
DFSsecond(1, 1);
buildTree();
/*
for(int i = 1; i <= N; i++){
printf("lant[ %d ] = %d\n", i, lant[i]);
}
printf("\n");
for(int i = 1; i <= nrLanturi; i++){
printf("Lantul %d are dimensiunea %d\n", i, dimensiuneLant[i]);
}
printf("\n");
for(int i = 1; i <= nrLanturi; i++){
printf("tataLant[ %d ] = %d\n", i, tataLant[i]);
}
printf("\n\n");
*/
for(int i = 1; i <= M; i++){
//printf("Inceput %d!\n", i);
int tip, X, Y;
fin >> tip >> X >> Y;
if(tip == 0){
//update
updateTree(tree[ lant[X] ], 1, 1, dimensiuneLant[ lant[X] ], posLant[X], Y);
}
else {
fout << query(X, Y) << "\n";
}
//printf("Sfarsit %d!\n", i);
//printf("\n\n");
}
return 0;
}