#include <fstream>
#include <vector>
#include <algorithm>
#include <iostream>
#define nrange 100000
int vals[nrange+1],nodeToChain[nrange+1],nodeToChainPos[nrange+1],
parentNode[nrange+1],nodeHeight[nrange+1],noAncestors[nrange+1];
std::vector<int> edge[nrange+1],topOfChain;
std::vector<std::vector<int>> chains;
struct intv_node
{
int val,l1,l2;
intv_node *c1,*c2,*p;
};
std::vector<intv_node*> intvTrees;
void UpdateIntvTree(intv_node*,std::vector<int>&);
void BuildChains(int);
void MarkParents(int);
void CountHeight(int,int);
void CountAncestors(int);
intv_node* BuildIntvTree(int,int);
intv_node* SearchIntvTree(intv_node*,int);
void update(int,int);
int querry(int,int);
int QuerryIntvTree(intv_node*,int,int,std::vector<int>&);
#define chainToIntvTree(a) intvTrees[a]
#define chainHeight(a) nodeHeight[topOfChain[a]]
#define check std::cout<<"check\n";
#define print(a) std::cout<<"print "<<a<<'\n';
#define print_chains \
{\
for(int i=0;i<chains.size();i++)\
{\
for(int j=0;j<chains[i].size();j++)\
std::cout<<chains[i][j]<<' ';\
std::cout<<'\n';\
}\
}
int main()
{
std::fstream fin("heavypath.in",std::ios::in),fout("heavypath.out",std::ios::out);
int n,m;
fin>>n>>m;
for(int i=1;i<=n;i++)fin>>vals[i];
for(int i=1;i<n;i++)
{
int a,b;
fin>>a>>b;
edge[a].push_back(b);
edge[b].push_back(a);
}
MarkParents(1);
CountHeight(1,0);
CountAncestors(1);
BuildChains(1);
//print(vals[7]);
for(int i=0;i<chains.size();i++)
intvTrees.push_back(BuildIntvTree(0,chains[i].size()));
for(int i=1;i<=n;i++)
{
int chainId=nodeToChain[i];
std::vector<int>&chain=chains[chainId];
int pos=nodeToChainPos[i];
intv_node *intvTreeRoot=chainToIntvTree(chainId);
intv_node *exactLeaf=SearchIntvTree(intvTreeRoot,pos);
UpdateIntvTree(exactLeaf,chain);
}
//print_chains
for(int i=1;i<=m;i++)
{
int t;
fin>>t;
if(t==0)
{
int x,val;
fin>>x>>val;
update(x,val);
}
else
{
int a,b;
fin>>a>>b;
fout<<querry(a,b)<<'\n';
}
}
}
void MarkParents(int node)
{
for(std::vector<int>::iterator it=edge[node].begin();
it!=edge[node].end();it++)
if(*it!=parentNode[node])
{
parentNode[*it]=node;
MarkParents(*it);
}
}
void CountHeight(int node,int h)
{
nodeHeight[node]=h;
for(std::vector<int>::iterator it=edge[node].begin();
it!=edge[node].end();it++)
if(*it!=parentNode[node])
CountHeight(*it,h+1);
}
void CountAncestors(int node)
{
int&noa=noAncestors[node];
noa=0;
for(std::vector<int>::iterator it=edge[node].begin();
it!=edge[node].end();it++)
if(*it!=parentNode[node])
{
CountAncestors(*it);
noa+=1+noAncestors[*it];
}
}
intv_node* SearchIntvTree(intv_node* node,int pos)
{
if(node->l1==node->l2)return node;
int l=(node->l1+node->l2)/2;
if(pos<=l)return SearchIntvTree(node->c1,pos);
return SearchIntvTree(node->c2,pos);
}
int QuerryIntvTree(intv_node* node,int l1,int l2,std::vector<int>&v)
{//print(node->l1) print(node->l2) print(l1) print(l2) check
if(l1==node->l1&&l2==node->l2)return node->val;
int l=(node->l1+node->l2)/2;
if(l1>l)return QuerryIntvTree(node->c2,l1,l2,v);
if(l2<=l)return QuerryIntvTree(node->c1,l1,l2,v);
int v1=QuerryIntvTree(node->c1,l1,l,v);
int v2=QuerryIntvTree(node->c2,l+1,l2,v);
if(vals[v[v1]]>vals[v[v2]])return v1;
return v2;
}
void UpdateIntvTree(intv_node *node,std::vector<int>&v)
{
if(node->l1==node->l2)
node->val=node->l1;
else
{
if(vals[v[node->c1->val]]>vals[v[node->c2->val]])
node->val=node->c1->val;
else node->val=node->c2->val;
}
if(node->p!=NULL)UpdateIntvTree(node->p,v);
}
intv_node* BuildIntvTree(int l1,int l2)
{
intv_node* intvNode=new intv_node;
intvNode->l1=l1;
intvNode->l2=l2;
intvNode->p=NULL;
intvNode->val=0;
if(l1==l2)
{
return intvNode;
}
int l=(l1+l2)/2;
intvNode->c1=BuildIntvTree(l1,l);
intvNode->c2=BuildIntvTree(l+1,l2);
intvNode->c1->p=intvNode;
intvNode->c2->p=intvNode;
return intvNode;
}
void BuildChains(int node)
{
int bestChild=0,valOfBest=0;
if((edge[node].size()==1&&node!=1)||edge[node].size()==0)
{
int chainId=chains.size();
std::vector<int>chain;
chain.push_back(node);
chains.push_back(chain);
nodeToChain[node]=chainId;
nodeToChainPos[node]=0;
topOfChain.push_back(node);
return;
}
for(std::vector<int>::iterator it=edge[node].begin();
it!=edge[node].end();it++)
if(*it!=parentNode[node])
{
if(noAncestors[*it]>valOfBest||bestChild==0)
{
valOfBest=noAncestors[*it];
bestChild=*it;
}
BuildChains(*it);
}
int chainId=nodeToChain[bestChild];
std::vector<int>&chain=chains[chainId];
nodeToChain[node]=chainId;
nodeToChainPos[node]=chain.size();
topOfChain[chainId]=node;
chain.push_back(node);
}
void update(int x,int val)
{
vals[x]=val;
int chainId=nodeToChain[x];
int posInChain=nodeToChainPos[x];
intv_node *intvTreeRoot=chainToIntvTree(chainId);
intv_node *exactLeaf=SearchIntvTree(intvTreeRoot,posInChain);
std::vector<int>&chain=chains[chainId];
UpdateIntvTree(exactLeaf,chain);
}
//int count;
int querry(int x1,int x2)
{//print(x1) print(x2) check
int chain1=nodeToChain[x1];
int chain2=nodeToChain[x2];
if(chain1==chain2)
{
int&chain=chain1;
int pos1=nodeToChainPos[x1];
int pos2=nodeToChainPos[x2];
if(pos2<pos1)std::swap<int>(pos1,pos2);
intv_node *intvTree=chainToIntvTree(chain);
return vals[chains[chain][QuerryIntvTree(intvTree,pos1,pos2,chains[chain])]];
}
if(chainHeight(chain2)>chainHeight(chain1))
{
std::swap<int>(x1,x2);
std::swap<int>(chain1,chain2);
}
int v1=QuerryIntvTree(chainToIntvTree(chain1),nodeToChainPos[x1],nodeToChainPos[topOfChain[chain1]],chains[chain1]);
//if(x1==7)std::cout<<vals[7]<<'\n';
int newX1=parentNode[topOfChain[chain1]];
int val2=querry(newX1,x2);
return std::max(vals[chains[chain1][v1]],val2);
}