#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define forEach(G) for(__typeof(G.begin()) it = G.begin() ; it != G.end() ; ++ it)
const int MAX_N = 100100;
const int INF = (1 << 30) - 1;
typedef const int cint;
int n,m;
int val[MAX_N];
vector<int> G[MAX_N];
vector<int> comp[MAX_N];
int under[MAX_N];
bool viz[MAX_N];
int belong[MAX_N];
int lvl[MAX_N];
int sz[MAX_N];
int tail[MAX_N];
int height[MAX_N];
int base[4*MAX_N];
int * AINT;
int mem[MAX_N];
int cl;
void dfs(cint nod)
{
int chosen = -1;
viz[nod] = 1;
forEach(G[nod]){
if(!viz[*it]){
lvl[*it] = lvl[nod] + 1;
dfs(*it);
under[nod] += under[*it];
if(chosen == -1 || under[chosen] < under[*it])
chosen = *it;
}
}
if(under[nod] == 0){
under[nod] = 1;
belong[nod] = ++cl;
sz[cl] = 1;
comp[cl].push_back(nod);
return;
}
belong[nod] = belong[chosen];
sz[belong[nod]]++;
comp[belong[nod]].push_back(nod);
forEach(G[nod]){
if(*it == chosen || lvl[*it] < lvl[nod])
continue;
tail[belong[*it]] = nod;
height[belong[*it]] = lvl[nod];
}
}
void build(cint nod,cint &left,cint &right,cint &path)
{
if(left == right){
AINT[nod] = val[comp[path][left-1]];
return;
}
int mid = (left+right)/2;
build(2*nod,left,mid,path);
build(2*nod+1,++mid,right,path);
AINT[nod] = max(AINT[2*nod],
AINT[2*nod+1]);
}
inline void build(cint &path)
{
AINT = base + mem[path];
build(1,1,sz[path],path);}
void update(cint nod,cint &left,cint &right,cint &pos,cint &path)
{
if(left == right){
AINT[nod] = val[comp[path][left-1]];
} else {
int mid = (left+right) / 2;
if(pos <= mid)
update(2*nod,left,mid,pos,path);
else update(2*nod+1,++mid,right,pos,path);
AINT[nod] = max(AINT[2*nod],
AINT[2*nod+1]);
}
}
inline void update(cint &nod)
{
int path = belong[nod];
int pos = lvl[nod] - height[path];
AINT = base + mem[path];
update(1,1,sz[path],pos,path);
}
int query(cint nod,cint &left, cint &right, cint &lo,cint &hi)
{
if(lo <= left && right <= hi)
return AINT[nod];
int mid = (left+right)/2;
int c1 = -INF , c2 = -INF;
if(lo <= mid)
c1 = query(2*nod,left,mid,lo,hi);
if(mid < hi)
c2 = query(2*nod+1,++mid,right,lo,hi);
if(c1 > c2)
return c1;
else return c2;
}
inline int query(cint &left,cint &right,cint &path)
{
AINT = base + mem[path];
return query(1,1,sz[path],left,right);
}
void solve()
{
int t,x,y;
while(m--){
scanf("%d%d%d",&t,&x,&y);
if(t == 0){
val[x] = y;
update(x);
} else {
int ans = 0;
while(true){
if(belong[x] == belong[y]){
if(lvl[x] > lvl[y])
swap(x,y);
const int aux =
query(lvl[x] - height[belong[x]],lvl[y] - height[belong[y]],belong[x]);
if(aux > ans)
ans = aux;
break;
} else {
if(height[belong[x]] < height[belong[y]])
swap(x,y);
const int aux =
query(1,lvl[x] - height[belong[x]],belong[x]);
if(aux > ans)
ans = aux;
x = tail[belong[x]];
}
}
printf("%d\n",ans);
}
}
}
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i = 1 ; i <= n ; ++ i)
scanf("%d",val+i);
int x,y;
for(int i = 1 ; i < n ; ++ i){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
lvl[1] = 1;
dfs(1);
for(int i = 1 ; i <= cl ; ++ i){
reverse(comp[i].begin(),comp[i].end());
mem[i] = mem[i-1] + sz[i-1] * 4;
build(i);
}
solve();
return 0;
}