#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cmath>
#include <cstring>
#include <ctime>
#include <unordered_map>
#include <iomanip>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define all(v) (v).begin(),(v).end()
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef pair<int,int> pii;
template<class T> ostream& operator<<(ostream& stream, const vector<T> v){ stream << "["; for (int i=0; i<(int)v.size(); i++) cout << v[i] << " "; stream << "]"; return stream; }
ll fpow(ll x, ll p, ll m){ll r=1; for (;p>>=1;){ if (p&1) r=r*x%m; x=x*x%m; } return r;}
int gcd(int a, int b){ if (!b) return a; return gcd(b,a%b);}
ll gcd(ll a, ll b){ if (!b) return a; return gcd(b,a%b);}
int N,M,a[100100],sz[100100],L,d[100100],lid[100100],pl[100100]; vi g[100100];
int pos[100100],off[100100];
int t[800100];
vi lant[100100];
void bdfs(int nod, int f, int h){
d[nod]=h;
sz[nod]=1;
if ((nod!=1 && g[nod].size()==1) || N==1){
lid[nod]=++L;
lant[L].pb(nod);
return;
}
int bst=0;
for (int nxt : g[nod]){
if (nxt==f) continue;
bdfs(nxt,nod,h+1);
if (sz[bst]<sz[nxt]) bst=nxt;
sz[nod]+=sz[nxt];
}
lid[nod]=lid[bst];
lant[lid[nod]].pb(nod);
for (int nxt : g[nod])
if (nxt!=f && nxt!=bst) pl[lid[nxt]]=nod;
}
void upd(int nod, int l, int r, int off, int p, int val){
if (l==r){
t[nod+off]=val;
return ;
}
int mid=(l+r)/2;
if (p<=mid) upd(nod*2,l,mid,off,p,val);
else upd(nod*2+1,mid+1,r,off,p,val);
t[nod+off]=max(t[nod*2+off],t[nod*2+1+off]);
}
void upd(int x, int val){
upd(1,1,lant[lid[x]].size(),off[lid[x]],pos[x],val);
}
int query(int nod, int l, int r, int ql, int qr, int off){
if (ql<=l && r<=qr) return t[nod+off];
int mid=(l+r)/2,lv=0,rv=0;
if (ql<=mid) lv=query(nod*2,l,mid,ql,qr,off);
if (mid<qr) rv=query(nod*2+1,mid+1,r,ql,qr,off);
return max(lv,rv);
}
void build(){
int i,j;
bdfs(1,0,1);
int crsz=0;
for (i=1; i<=L; i++){
reverse(all(lant[i]));
off[i]=crsz;
for (j=1; j<=(int)lant[i].size(); j++){
pos[lant[i][j-1]]=j;
upd(lant[i][j-1],a[lant[i][j-1]]);
}
crsz+=4*lant[i].size();
}
}
int query(int x, int y){
int res=0;
while (x!=-1){
if (d[x]>d[y]) swap(x,y);
if (lid[x]==lid[y]){
res=max(res,query(1,1,lant[lid[x]].size(),pos[x],pos[y],off[lid[x]]));
x=-1;
}
else {
if (d[pl[lid[x]]]<d[pl[lid[y]]]) swap(x,y);
res=max(res,query(1,1,lant[lid[x]].size(),1,pos[x],off[lid[x]]));
x=pl[lid[x]];
}
}
return res;
}
int main(){
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
fin >> N >> M;
int i;
for (i=1; i<=N; i++)
fin >> a[i];
for (i=1; i<N; i++){
int x,y;
fin >> x >> y;
g[x].pb(y);
g[y].pb(x);
}
build();
for (int k=1; k<=M; k++){
int t,x,y;
fin >> t >> x >> y;
if (t==0){
a[x]=y;
upd(x,y);
}
else {
fout << query(x,y) << "\n";
}
}
return 0;
}