#include <bits/stdc++.h>
using namespace std;
const int NMAX = 100005;
vector <int> Edge[NMAX];
int last = 0 , time1 = 0 , n;
int freq[NMAX],size_tree[NMAX],com[NMAX], parent[NMAX],value[NMAX] , Heavy_Edge[NMAX] , poz[NMAX] , start[NMAX], aint[4*NMAX + 5];
int d[NMAX], parent1[NMAX] , height[NMAX] , best[NMAX] , end1[NMAX] , max_t[NMAX];
int _in_loc; char _in_buff[4096];
char read_ch()
{
++_in_loc;
if (_in_loc == 4096) {
_in_loc = 0;
fread(_in_buff, 1, 4096, stdin);
}
return _in_buff[_in_loc];
}
int read_u32()
{
int u32 = 0; char c;
while (!isdigit(c = read_ch()) && c != '-');
int sgn = 1;
if (c == '-') {
sgn = -1;
} else {
u32 = c - '0';
}
while (isdigit(c = read_ch())) {
u32 = u32 * 10 + c - '0';
}
return u32 * sgn;
}
void dfs(int nod)
{
freq[nod] = 1;
for(auto it : Edge[nod])
if(!freq[it])
{
d[it] = d[nod] + 1;
parent[it]=nod;
dfs(it);
size_tree[nod]+= size_tree[it];
}
bool ok = 0 ;
for(auto it : Edge[nod])
if(it!=parent[nod] && size_tree[it] >= (size_tree[nod] + 1)/2)
{
ok = 1;
com[nod] = com[it];
best[com[it]] = max(best[com[it]] , value[nod]);
Heavy_Edge[it] = nod;
break;
}
if(!ok)
{
com[nod] = ++last;
best[last] = value[nod];
start[last] = nod;
}
for(auto it: Edge[nod])
if(it != parent[nod] && com[nod] != com[it])
parent1[com[it]] = nod;
}
void dfs1(int nod)
{
poz[++time1] = nod;
height[nod] = time1;
end1[com[nod]] = nod;
if(Heavy_Edge[nod])
dfs1(Heavy_Edge[nod]),max_t[height[nod]] = max(max_t[height[nod]] , value[nod]);
else
max_t[time1] = value[nod];
}
void update(int nod ,int st , int dr , int poz,int val)
{
if(st == dr)
aint[nod]=val;
else
{
int med = (st + dr)>>1;
if(poz<=med)update(2*nod , st,med,poz,val);
else
update(2*nod + 1 , med+1,dr,poz,val);
aint[nod]=max(aint[2*nod],aint[2*nod+1]);
}
}
int query(int nod ,int st, int dr,int l,int r)
{
if(l<=st&&dr<=r)
return aint[nod];
int med=(st+dr)>>1;
int a = 0 ,b=0;
if(l<=med)a=query(2*nod,st,med,l,r);
if(r>med)
b=query(2*nod+1,med+1,dr,l,r);
return max(a,b);
}
int lca(int a , int b)
{
if(a == b)return a;
if(d[a] >= d[b])return lca(parent[a] , b);
return lca(a , parent[b]);
}
int answer(int x , int y)
{
if(d[x] > d[y]) swap(x , y);
int x1 = com[x] , y1 = com [y];
if(x1 == y1)
return query(1 , 1 , n, min(height[x] , height[y]), max(height[x] , height[y]));
else
{
int maxim = 0 , y2 = parent1[y1];
while(com[y2] != x1)
{
if(y2 == 0)break;
maxim = max(maxim , best[com[y2]]);
y2 = parent1[com[y2]];
}
int a = query(1 , 1 , n, min(height[y2] , height[x]), max(height[y2],height[x]));
int b = max_t[height[y]];
maxim = max(maxim , max(a,b));
return maxim;
}
}
void solve(int x , int y)
{
int t = lca(x , y);
printf("%d\n",max(answer(x,t) , answer(y, t)));
}
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
int q , i , x , y, op;
n=read_u32();
q=read_u32();
for( i = 1 ; i <= n; i++)
{
value[i]=read_u32();
size_tree[i] = 1;
}
for( i = 1 ; i < n; i++)
{
x = read_u32();
y = read_u32();
Edge[x].push_back(y);
Edge[y].push_back(x);
}
d[1] = 1;
parent[1] = 1;
dfs(1);
for(i = 1 ; i <=last ; i++)
dfs1(start[i]);
for(i = 1 ; i <= n ; i++)
update(1 , 1 , n , i , value[poz[i]]);
for(i = 1 ; i <= q; i++)
{
op=read_u32();
x=read_u32();
y=read_u32();
if(op == 0)
update(1 , 1 , n , height[x] , y);
else
solve(x,y);
}
return 0;
}