#include<iostream>
#include<fstream>
#include<cstring>
#include<vector>
using namespace std;
struct node {
int id;
node *next;
}*graf[100005], *v;
int n,m;
int val[100005], subTreeSize[100005], lev[100005];
int pozInChain[100005], chainId[100005], father[100005], nrChains;
int *aint[100005];
vector<int> chain[100005];
void makeChains(int x, int l) {
int heavyChild = -1;
int weight = 0;
lev[x]=l;
subTreeSize[x]=1;
for (node *p = graf[x]; p; p=p->next)
if (p->id != father[x]) {
father[p->id]=x;
makeChains(p->id,l+1);
subTreeSize[x]+=subTreeSize[p->id];
if (subTreeSize[p->id]>weight) { weight = subTreeSize[p->id]; heavyChild = p->id; }
}
if (heavyChild == -1) {
++nrChains;
chain[nrChains].push_back(x);
pozInChain[x]=1;
chainId[x]=nrChains;
}
else {
chain[chainId[heavyChild]].push_back(x);
pozInChain[x]=chain[chainId[heavyChild]].size();
chainId[x]=chainId[heavyChild];
}
}
void init(int line, int nod, int l, int r) {
if (l==r) aint[line][nod]=val[chain[line][l-1]];
else {
int mid=(l+r)/2;
init(line,2*nod,l,mid);
init(line,2*nod+1,mid+1,r);
aint[line][nod]=max(aint[line][2*nod],aint[line][2*nod+1]);
}
}
void update(int line, int nod, int l, int r, int poz) {
if (l==r) aint[line][nod]=val[chain[line][l-1]];
else {
int mid=(l+r)/2;
if (poz<=mid) update(line,2*nod,l,mid,poz);
else update(line,2*nod+1,mid+1,r,poz);
aint[line][nod]=max(aint[line][2*nod],aint[line][2*nod+1]);
}
}
int queryAint(int line, int nod, int l, int r, int x, int y){
if (l>=x && r<=y) return aint[line][nod];
else {
int mid = (l+r)/2;
int v1=0, v2=0;
if (x<=mid) v1=queryAint(line,2*nod,l,mid,x,y);
if (y>mid) v2=queryAint(line,2*nod+1,mid+1,r,x,y);
return max(v1,v2);
}
}
int query(int x, int y) {
if (chainId[x]==chainId[y]) {
return queryAint(chainId[x],1,1,chain[chainId[x]].size(),min(pozInChain[x],pozInChain[y]),max(pozInChain[x],pozInChain[y]));
}
else {
int lx = lev[father[chain[chainId[x]][chain[chainId[x]].size()-1]]];
int ly = lev[father[chain[chainId[y]][chain[chainId[y]].size()-1]]];
if (lx>ly) {
int maxc = queryAint(chainId[x],1,1,chain[chainId[x]].size(),pozInChain[x],chain[chainId[x]].size());
return max(maxc,query(father[chain[chainId[x]][chain[chainId[x]].size()-1]],y));
}
else {
int maxc = queryAint(chainId[y],1,1,chain[chainId[y]].size(),pozInChain[y],chain[chainId[y]].size());
return max(maxc,query(father[chain[chainId[y]][chain[chainId[y]].size()-1]],x));
}
}
}
int main(void) {
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
cin>>n>>m;
for (int i=1; i<=n; ++i) cin>>val[i];
for (int i=1; i<n; ++i) {
int x,y; cin>>x>>y;
v = new node(); v->id=x; v->next=graf[y]; graf[y]=v;
v = new node(); v->id=y; v->next=graf[x]; graf[x]=v;
}
//build chains
makeChains(1,1);
//build aint
for (int i=1; i<=nrChains; ++i) {
aint[i]=new int[chain[i].size()*4+5];
init(i, 1, 1, chain[i].size());
}
for (int i=1; i<=m; ++i) {
int t, x, y;
cin>>t>>x>>y;
if (t==0) {
val[x]=y;
update(chainId[x],1,1,chain[chainId[x]].size(),x);
}
else {
cout<<query(x,y)<<"\n";
}
}
return 0;
}