#include<bits/stdc++.h>
using namespace std;
#define INIT ios_base :: sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define mp make_pair
#define pb push_back
#define ft first
#define sc second
#define ll long long
#define pii pair<int, int>
#define count_bits __builtin_popcount
#define int ll
inline char get_ (){
const int oo=1000005;
static char buf[oo], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, oo, stdin), p1 == p2) ? EOF : *p1 ++;
}
int read_ () {
char c = get_();
int sum = 0;
while(!(c >= '0' && c <= '9')) c = get_();
while(c >= '0' && c <= '9') sum = sum * 10 + (c - '0'), c = get_();
return sum;
}
int n, m, v[100010];
vector<int> g[100010];
int pos[100010];
int hd[100010];
int par[100010];
int val[100010];
int sz[100010];
bool vr[100010];
//graph traversals and perequisites
void dfs_sz(int s){
vr[s]=true;
int res=1;
for(auto u:g[s]){
if(!vr[u]){
par[u]=s;
dfs_sz(u);
res+=sz[u];
}
}
vr[s]=false;
sz[s]=res;
}
int tmp=0;
int tmp1=0, ent[100010], ex[100010];
void build_path(int s, int h){
tmp++;
tmp1++;
ent[s]=tmp1;
pos[s]=tmp;
val[pos[s] ]=v[s];
hd[s]=h;
pii nxt={0, 0};
for(auto u:g[s]){
if(u!=par[s]){nxt=max(nxt, {sz[u], u});}
}
if(nxt!=mp(0ll, 0ll) ){
build_path(nxt.sc, h);
}
for(auto u:g[s]){
if( (u!=par[s]) && (u!=nxt.sc) ){
build_path(u, u);
}
}
tmp1++;
ex[s]=tmp1;
return;
}
//segtree
int tree[400010];
void build_seg(int v, int l, int r){
if(l==r){
tree[v]=val[l];
return;
}
int m=(l+r)>>1ll;
build_seg(v*2, l, m); build_seg(2*v+1, m+1, r);
tree[v]=max(tree[v*2], tree[v*2+1]);
}
int query(int v, int tl, int tr, int l, int r){
if(l>r){
return 0;
}
if( (tl==l) && (tr==r) ){
return tree[v];
}
int m=(tl+tr)>>1ll;
return max( query(v*2, tl, m, l, min(r, m)), query(v*2+1, m+1, tr, max(l, m+1), r ) );
}
void update(int v, int l, int r, int x, int y){
if(l==r){
tree[v]=val[x]=y;
return;
}
int m=(l+r)>>1ll;
if(x<=m){
update(v*2, l, m, x, y);
}
else{
update(2*v+1, m+1, r, x, y);
}
tree[v]=max(tree[v*2], tree[v*2+1] );
}
//LCA
int anc[100010][20];
void build_lca(){
for(int i=1; i<=n; i++){
anc[i][0]=par[i];
}
for(int j=1; j<=18; j++){
for(int i=1; i<=n; i++){
anc[i][j]=anc[anc[i][j-1] ][j-1];
}
}
}
bool is_anc(int u, int v){
return ent[u]<ent[v] && ex[u]>ex[v];
}
int find_lca(int u, int v){
if(is_anc(u, v)){
return u;
}
if(is_anc(v, u) ){
return v;
}
int ac=u;
for(int j=18; j>=0; j--){
if( (anc[ac][j]!=0) && ( !is_anc(anc[ac][j], v ) ) ){
ac=anc[ac][j];
}
}
return anc[ac ][0];
}
//get_max answers for a chain from the vertex to an ancestor
//v is anc
int get_max(int u, int v){
if(hd[u]==hd[v]){
return query(1, 1, n, pos[v], pos[u]);
}
return max( query(1, 1, n, pos[hd[u] ], pos[u]), get_max(par[hd[u] ], v) );
}
ifstream fin("heavypath.in"); ofstream fout("heavypath.out");
#define cin fin
#define cout fout
int32_t main(){
INIT
cin>>n>>m;
for(int i=1; i<=n; i++){
cin>>v[i];
}
for(int i=1; i<n; i++){
int a,b;
cin>>a>>b;
g[a].pb(b);
g[b].pb(a);
}
dfs_sz(1);
build_path(1, 1);
build_seg(1, 1, n);
build_lca();
/*
for(int i=1; i<=n; i++){
cout<<hd[i]<<" ";
}
cout<<"\n"<<flush;
*/
for(int i=1; i<=m; i++){
int t, x, y;
cin>>t>>x>>y;
if(t==0){
update(1, 1, n, pos[x], y);
}
else{
int m1=0, m2=0;
int lca=find_lca(x, y);
//cout<<lca<<"\n"<<flush;
m1=get_max(x, lca), m2=get_max(y, lca);
cout<<max(m1, m2)<<"\n";
}
}
return 0;
}