#include <fstream>
#include <algorithm>
#include <iomanip>
#include <vector>
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
const int maxn=1e5+5;
vector<int> adj[maxn];
int vals[maxn];
int val[maxn];
int tin[maxn];
int tout[maxn];
int poznod[maxn];
int primul[maxn];
int fvval[maxn];
int subtree[maxn];
int binary_lift[maxn][17];
vector<vector<int>> aint;
int cnt=1;
int cnt2=1;
int n,q;
void dfs(int nod,int par) {
subtree[nod]=1;
binary_lift[nod][0]=par;
tin[nod]=cnt2++;
int maxsubtree=0,valmax=0;
for (auto elem:adj[nod]) {
if (elem!=par) {
dfs(elem,nod);
subtree[nod]+=subtree[elem];
if (subtree[elem]>maxsubtree) {
maxsubtree=subtree[elem];
valmax=val[elem];
}
}
}
if (maxsubtree == 0) {
val[nod]=cnt++;
}else val[nod]=valmax;
tout[nod]=cnt2++;
}
void update(int nod,int l,int r,int poz,int val,int grupa) {
if (l>poz || r<poz)return;
if (l==poz && r==poz) {
aint[grupa][nod]=val;
return;
}
int mid=(l+r)/2;
update(nod*2,l,mid,poz,val,grupa);
update(nod*2+1,mid+1,r,poz,val,grupa);
aint[grupa][nod]=max(aint[grupa][nod*2],aint[grupa][nod*2+1]);
}
int query(int nod,int l,int r,int st,int dr,int grupa) {
if (l>dr || r<st)return 0;
if (l>=st && r<=dr)return aint[grupa][nod];
int mid=(l+r)/2;
return max(query(nod*2,l,mid,st,dr,grupa),query(nod*2+1,mid+1,r,st,dr,grupa));
}
bool isancestor(int nod1,int nod2) {
return (tin[nod1]<=tin[nod2] && tout[nod1]>=tout[nod2]);
}
void dfs2(int nod,int par) {
fvval[val[nod]]++;
if (primul[val[nod]]==0)primul[val[nod]]=nod;
poznod[nod]=fvval[val[nod]];
for (auto elem:adj[nod]) {
if (elem!=par) {
dfs2(elem,nod);
}
}
}
int lca(int u,int v) {
if (isancestor(u,v))return u;
if (isancestor(v,u))return v;
int nod=u;
for (int i=16;i>=1;i--) {
if (isancestor(binary_lift[nod][i],v)==0 && binary_lift[nod][i]!=0) {
nod=binary_lift[nod][i];
}
}
return binary_lift[nod][0];
}
int solve(int nod1,int nod2) {
if (val[nod1]==val[nod2]) {
return query(1,1,fvval[val[nod1]],min(poznod[nod1],poznod[nod2]),max(poznod[nod1],poznod[nod2]),val[nod1]);
}
int z;
int nod3=primul[val[nod1]];
z=query(1,1,fvval[val[nod1]],poznod[nod3],poznod[nod1],val[nod1]);
return max(solve(binary_lift[primul[val[nod1]]][0],nod2),z);
}
signed main() {
cin>>n>>q;
for (int i=1;i<=n;i++) {
cin>>vals[i];
}
for (int i=1;i<n;i++) {
int l,r;
cin>>l>>r;
adj[l].push_back(r);
adj[r].push_back(l);
}
dfs(1,0);
dfs2(1,0);
aint.resize(cnt+1);
for (int j=1;j<=16;j++) {
for (int i=1;i<=n;i++) {
binary_lift[i][j]=binary_lift[binary_lift[i][j-1]][j-1];
}
}
for (int i=1;i<=cnt-1;i++) {
aint[i].resize(4*fvval[i]+1);
}
for (int i=1;i<=n;i++) {
int gr=val[i];
update(1,1,fvval[gr],poznod[i],vals[i],gr);
}
while (q--) {
int t,x,y;
cin>>t>>x>>y;
if (t==0) {
int gr=val[x];
update(1,1,fvval[gr],poznod[x],y,gr);
}else {
int lcaa=lca(x,y);
cout<<max(solve(x,lcaa),solve(y,lcaa))<<'\n';
}
}
return 0;
}