#include <fstream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
class Seg_tree
{
int n,minn;
vector<int>aint;
void build(vector<int>&a,int nod,int st,int dr)
{
if(st==dr)
{
aint[nod]=a[st];
return;
}
int m=(st+dr)/2;
build(a,2*nod,st,m);
build(a,2*nod+1,m+1,dr);
aint[nod]=max(aint[2*nod],aint[2*nod+1]);
}
void update(int nod,int st,int dr,const int& poz,const int& val)
{
if(st>poz || dr<poz)return;
if(st==dr)
{
aint[nod]=val;
return;
}
int m=(st+dr)/2;
update(2*nod,st,m,poz,val);
update(2*nod+1,m+1,dr,poz,val);
aint[nod]=max(aint[2*nod],aint[2*nod+1]);
}
int query(int nod,int st,int dr,const int& l,const int& r)
{
if(st>r || dr<l)return minn;
if(st>=l && dr<=r)
{
return aint[nod];
}
int m=(st+dr)/2;
return max(query(2*nod,st,m,l,r),query(2*nod+1,m+1,dr,l,r));
}
public:
Seg_tree(vector<int>&a,int x)
{
n=(int)a.size()-1;
aint.resize(4*n+1);
build(a,1,1,n);
minn=x;
}
Seg_tree()
{
}
void update(int poz,int val)
{
update(1,1,n,poz,val);
}
int query(int l,int r)
{
return query(1,1,n,l,r);
}
};
class heavy
{
vector<int>e={0};
Seg_tree aint;
vector<int>poz;
vector<int>dp,t,h,head;
int n;
void dfs1(vector<vector<int>>&g,int nod,int tata)
{
h[nod]=h[tata]+1;
t[nod]=tata;
dp[nod]=1;
for(auto &c:g[nod])
{
if(c==tata)continue;
dfs1(g,c,nod);
dp[nod]+=dp[c];
}
}
void dfs2(vector<vector<int>>&g,vector<int>&val,const int& nod,const int& tata)
{
poz[nod]=(int)e.size();
e.push_back(val[nod]);
int maxx=0;
dp[0]=0;
for(auto &c:g[nod])
{
if(c==tata)continue;
if(dp[c]>dp[maxx])
{
maxx=c;
}
}
if(dp[nod]>1)
{
head[maxx]=head[nod];
dfs2(g,val,maxx,nod);
for(auto &c:g[nod])
{
if(c==tata || c==maxx)
{
continue;
}
head[c]=c;
dfs2(g,val,c,nod);
}
}
}
void dfs(vector<vector<int>>&g,vector<int>val)
{
dfs1(g,1,0);
dfs2(g,val,1,0);
}
public:
heavy(vector<vector<int>>&g,vector<int>&val)
{
n=(int)g.size()-1;
poz.resize(n+1);
dp.resize(n+1);
t.resize(n+1);
h.resize(n+1);
poz.resize(n+1);
head.resize(n+1);
head[1]=1;
h[0]=0;
dfs(g,val);
aint=Seg_tree(e,0);
}
void update(int nod,int val)
{
aint.update(poz[nod],val);
}
int query(int a,int b)
{
int rez=0;
for(;head[a]!=head[b];b=t[head[b]])
{
if(h[head[a]]>h[head[b]])
{
swap(a,b);
}
rez=max(rez,aint.query(poz[head[b]],poz[b]));
}
if(h[a]>h[b])
{
swap(a,b);
}
rez=max(rez,aint.query(poz[a],poz[b]));
return rez;
}
};
int main()
{
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int n,q;
cin>>n>>q;
vector<int>val(n+1,0);
vector<vector<int>>a(n+1);
for(int i=1;i<=n;i++)cin>>val[i];
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
a[x].push_back(y);
a[y].push_back(x);
}
heavy tree(a,val);
while(q--)
{
int cer;
cin>>cer;
if(cer)
{
int l,r;
cin>>l>>r;
cout<<tree.query(l,r)<<'\n';
}
else
{
int poz,val;
cin>>poz>>val;
tree.update(poz,val);
}
}
}