#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
ifstream fin("heavypath.in"); ofstream fout("heavypath.out");
#define cin fin
#define cout fout
int n, m, a[100010];
vector<int> g[100010];
int sz[100010];
int ent[100010], ex[100010];
int tmp=0;
bool v[100010];
int anc[100010][21];
void dfs0(int s){
sz[s]=1;
tmp++;
ent[s]=tmp;
v[s]=true;
for(auto u:g[s]){
if(!v[u]){
anc[u][0]=s;
dfs0(u);
sz[s]+=sz[u];
}
}
tmp++;
ex[s]=tmp;
v[s]=false;
return;
}
int rep[100010];
int crd[100010];
void dfs1(int s){
tmp++;
crd[s]=tmp;
int mx=0, node=0;
for(auto u:g[s]){
if(u!=anc[s][0]){
if(sz[u]>mx){
node=u;
mx=sz[u];
}
}
}
if(node!=0){
rep[node]=s;
dfs1(node);
}
for(auto u:g[s]){
if( (u!=node) && ( u!=anc[s][0] ) ){
rep[u]=u;
dfs1(u);
}
}
}
void build_anc(){
for(int j=1; j<=16; 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 lca(int u, int v){
if( is_anc(u, v)){
return u;
}
if( is_anc(v, u)){
return v;
}
int res=u;
for(int j=16; j>=0; j--){
if( (anc[res][j]!=0 ) && ( !is_anc( anc[res][j], v ) ) ){
res=anc[res][j];
}
}
return anc[res][0];
}
int b[100010];
int tree[100010];
void build_tree(int v, int l, int r){
if(l==r){
tree[v]=b[l];
return;
}
int mid=(l+r)>>1ll;
build_tree(2*v,l, mid); build_tree(2*v+1, mid+1, r);
tree[v]=max(tree[2*v], tree[2*v+1]);
return;
}
void update(int v, int l, int r, int p, int x){
if(l==r){
b[ crd[p] ]=x;
tree[v]=b[ crd[p] ];
return;
}
int mid=(l+r)>>1ll;
if(crd[p]<=mid){
update(2*v, l, mid, p, x);
}
else{
update(2*v+1, mid+1, r, p, x);
}
tree[v]=max(tree[v*2], tree[2*v+1]);
return;
}
int query(int v, int tl, int tr, int l, int r){
if(l>r){
return -1;
}
if( (tl==l) && (tr==r)){
return tree[v];
}
int mid=(tl+tr)>>1ll;
return max( query(2*v, tl, mid, l, min(r, mid)), query(2*v+1, mid+1, tr, max(l, mid+1), r ) );
}
int32_t main(){
INIT
cin>>n>>m;
for(int i=1; i<=n; i++){
cin>>a[i];
}
for(int i=1; i<n; i++){
int u, v;
cin>>u>>v;
g[u].pb(v); g[v].pb(u);
}
dfs0(1);
build_anc();
tmp=0;
rep[1]=1;
dfs1(1);
for(int i=1; i<=n; i++){
b[crd[i] ]=a[i];
}
build_tree(1, 1, n);
for(int i=1; i<=m; i++){
int t;
cin>>t;
if(t==0){
int p, x;
cin>>p>>x;
update(1, 1, n, p, x);
}
else{
int u, v;
cin>>u>>v;
int LCA=lca(u, v);
int mx1=0, mx2=0;
int ac=u;
while(true){
if( rep[ac]!=LCA ){
if( (is_anc(rep[ac], LCA)) ){
mx1=max(mx1, query(1, 1, n, crd[ LCA], crd[ac]) );
break;
}
else{
mx1=max(mx1, query( 1, 1, n, crd[ rep[ac] ], crd[ac ]) );
ac=anc[ rep[ac] ][0];
continue;
}
}
else{
mx1=max(mx1, query( 1, 1, n, crd[ rep[ac] ], crd[ac ]) );
break;
}
}
ac=v;
while(true){
if(rep[ac]!=LCA){
if(is_anc(rep[ac], LCA )){
mx2=max(mx2, query(1, 1, n, crd[LCA], crd[ac] ) );
break;
}
else{
mx2=max( mx2, query(1, 1, n, crd[rep[ac] ], crd[ac]) );
ac=anc[rep[ac] ][0];
continue;
}
}
else{
mx2=max(mx2, query(1, 1, n, crd[rep[ac] ], crd[ac] ) );
break;
}
}
cout<<max(mx1, mx2)<<"\n";
}
}
return 0;
}