#include <stdio.h>
#include <vector>
#include <iostream>
#include <algorithm>
#define NMAX 100005
using namespace std;
FILE *fin = fopen("heavypath.in", "r");
FILE *fout = fopen("heavypath.out", "w");
vector <int> graf[NMAX];
vector <int> drum[NMAX];
vector <int> arbint[NMAX];
int n,m,t,x,y,a[NMAX],nrlant,lant[NMAX],tata[NMAX],nivel[NMAX],poz,ans,i;
bool viz[NMAX];
void dfs(int nod, int niv)
{
int maxim,imax,i,t,ultim;
// fprintf(fout,"%d ",nod);
viz[nod] = true;
nivel[nod] = niv;
/* if(graf[nod].size() == 1)
{
nrlant++;
lant[nod] = nrlant;
drum[nrlant].push_back(nod);
tata[nrlant] = graf[nod][0];
// return;
}*/
maxim = 0;
int fii=0;
for(i=0; i<=graf[nod].size()-1; ++i)
{
if(!viz[graf[nod][i]])
{ fii++;
dfs(graf[nod][i], niv+1);
if(drum[lant[graf[nod][i]]].size() > maxim)
{
maxim = drum[lant[graf[nod][i]]].size();
imax = lant[graf[nod][i]];
ultim=graf[nod][i];
}
}
// if(nivel[graf[nod][i]] < nivel[nod])
// t = graf[nod][i];
}
if(fii==0)
{
nrlant++;
lant[nod] = nrlant;
drum[nrlant].push_back(nod);
return;
}
lant[nod] = imax;
drum[imax].push_back(nod);
// tata[imax] = t;
// fprintf(fout,"nodul %d se ataseaza nodului %d\n",nod,ultim);
for(i=0; i<=graf[nod].size()-1; ++i)
if( graf[nod][i]!=ultim and nivel[graf[nod][i]]>nivel[nod])
{tata[lant[graf[nod][i]]]=nod;
// fprintf(fout,"%d este tatal lantului nodului %d cu numarul % d\n",nod, graf[nod][i], lant[graf[nod][i]]);
}
}
void build(int index, int nod, int st, int dr)
{
int mij;
if(st == dr)
{
arbint[index][nod] = a[drum[index][st]];
return;
}
mij = (st+dr) /2;
build(index, 2*nod, st, mij);
build(index, 2*nod+1, mij+1, dr);
arbint[index][nod] = max(arbint[index][2*nod], arbint[index][2*nod+1]);
}
void update(int index, int nod, int st, int dr, int poz, int val)
{
int mij;
if(st == dr)
{
arbint[index][nod] = val;
return;
}
mij = (st+dr) /2;
if(poz <= mij)
update(index, 2*nod, st, mij, poz, val);
else
update(index, 2*nod+1, mij+1, dr, poz, val);
arbint[index][nod] = max(arbint[index][2*nod], arbint[index][2*nod+1]);
}
int query(int index, int nod, int st, int dr, int a, int b)
{
int ans, mij;
if(a<=st and dr<=b)
return arbint[index][nod];
ans = 0;
mij = (st+dr) /2;
if(a <= mij)
ans = max(ans, query(index, 2*nod, st, mij, a, b));
if(b > mij)
ans = max(ans, query(index, 2*nod+1, mij+1, dr, a, b));
return ans;
}
int main()
{
fscanf(fin, "%d%d", &n,&m);
for(i=1; i<=n; ++i)
fscanf(fin, "%d", &a[i]);
for(i=1; i<=n-1; ++i)
{
fscanf(fin, "%d%d", &x,&y);
graf[x].push_back(y);
graf[y].push_back(x);
}
dfs(1, 1);
//fprintf(fout,"\n");
for(i=1; i<=nrlant; ++i)
{
reverse(drum[i].begin(), drum[i].end());
// for(int k=0;k<drum[i].size();k++){
// int t=drum[i][k];
// fprintf(fout,"%d ",t);}
// fprintf(fout,"tata %d si nivel tata %d ",tata[i],nivel[tata[i]]);
// fprintf(fout,"\n");
arbint[i].resize(4*drum[i].size());
}
for(i=1; i<=nrlant; ++i){
build(i, 1, 0, drum[i].size()-1);
// for(int k=1;k<=12;k++)
// fprintf(fout,"%d %d ",k, arbint[i][k]);
// fprintf(fout,"\n");
}
while(m--)
{
fscanf(fin, "%d%d%d", &t,&x,&y);
if(t == 0)
{
a[x] = y;
poz = (-1)*(nivel[tata[lant[x]]] - nivel[x] + 1);
update(lant[x], 1, 0, drum[lant[x]].size()-1, poz, y);
}
else
{
ans = 0;
while(lant[x] != lant[y])
{
if(nivel[tata[lant[x]]] < nivel[tata[lant[y]]])
swap(x, y);
int a=(-1)*( nivel[tata[lant[x]]] - nivel[x] + 1);
int b=drum[lant[x]].size()-1;
ans = max(ans, query(lant[x], 1, 0, drum[lant[x]].size()-1,0,(-1)*( nivel[tata[lant[x]]] - nivel[x] + 1)));
x = tata[lant[x]];
}
if((nivel[tata[lant[x]]] - nivel[x] +1)*(-1) > (nivel[tata[lant[y]]]- nivel[y]+1)*(-1))
swap(x,y);
// fprintf(fout,"%d %d %d ", drum[lant[x]].size()-1, (-1)*(nivel[tata[lant[x]]] - nivel[x] + 1), (-1)*(nivel[tata[lant[y]]] - nivel[y] + 1));
ans = max(ans, query(lant[x], 1, 0, drum[lant[x]].size()-1,(-1)*( nivel[tata[lant[x]]] - nivel[x] + 1), (-1)*(nivel[tata[lant[y]]] - nivel[y] + 1)));
fprintf(fout, "%d\n", ans);
}
}
fclose(fin);
fclose(fout);
return 0;
}