#include <fstream>
#include <vector>
using namespace std;
const int nmax = 1e5 + 1;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
vector <int> g[nmax];
int n , m , x , y , v[nmax] , sz[nmax] , hvc[nmax], ind , poz[nmax] , tin[nmax] , tout[nmax] , tm;
int c[nmax] , t[nmax] , op;
struct segt
{
int aint[4*nmax];
void update(int nod , int st, int dr, int &new_value, int &poz)
{
if(st == dr) aint[nod] = new_value;
else
{
int mj = (st+dr)/2;
if(poz <= mj) update(nod*2,st,mj,new_value,poz);
else update(nod*2+1,mj+1,dr,new_value,poz);
aint[nod] = max(aint[nod*2],aint[nod*2+1]);
}
}
int query(int nod , int st, int dr , int&qst, int&qdr)
{
if(qst<=st && dr<=qdr) return aint[nod];
else
{
int val = -1;
int mj = (st+dr)/2;
if(qst<=mj) val = max(val,query(nod*2,st,mj,qst,qdr));
if(qdr>mj) val = max(val,query(nod*2+1,mj+1,dr,qst,qdr));
return val;
}
}
}arb;
bool isanc(int &x , int &y)
{
return(tin[x]<=tin[y]&&tout[y]<=tout[x]);
}
void siz(int x , int p)
{
sz[x] = 1;
for(auto it : g[x])
{
if(it!=p)
{
siz(it,x);
sz[x] += sz[it];
}
}
for(auto it : g[x])
{
if(it!=p && sz[it]>sz[x]/2)
{
hvc[x] = it;
break;
}
}
}
void hp(int x , int p , int cap)
{
t[x] = p;
c[x] = cap;
tin[x] = ++tm;
poz[x] = ++ind;
arb.update(1,1,n,v[x],ind);
if(hvc[x])
{
hp(hvc[x],x,cap);
}
for(auto it : g[x])
{
if(it == p || it == hvc[x]) continue;
hp(it,x,it);
}
tout[x] = ++tm;
}
signed main()
{
cin >> n >> m;
for(int i = 1 ; i <= n ; ++i)
{
cin >> v[i];
}
for(int i = 1 ; i < n ; ++i)
{
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
siz(1,0);
hp(1,0,1);
for(int i = 1 ; i <= m ; ++i)
{
cin >> op >> x >> y;
if(op == 0)
{
arb.update(1,1,n,y,poz[x]);
}
else
{
int mx = -1;
while(true)
{
if(isanc(c[x],y)) break;
mx = max(mx,arb.query(1,1,n,poz[c[x]],poz[x]));
x = t[c[x]];
}
while(true)
{
if(isanc(c[y],x)) break;
mx = max(mx,arb.query(1,1,n,poz[c[y]],poz[y]));
y = t[c[y]];
}
int pmn = min(poz[x],poz[y]);
int pmx = max(poz[x],poz[y]);
mx = max(mx,arb.query(1,1,n,pmn,pmx));
cout << mx << '\n';
}
}
return 0;
}