#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
#define NMAX 100005
vector<int> graf[NMAX];
int gsize[NMAX];
int deph[NMAX];
int v[NMAX];
int what_path[NMAX];
int what_poz[NMAX];
struct path
{
int father;
vector<int> noduri;
};
struct elem
{
int st,dr;
int maxim;
};
vector<path> paths;
class arbint
{
public:
vector<elem> arb;
int nr;
arbint(int s)
{
arb.clear();
nr=s;
}
void create(int s)
{
arb.resize(4*s);
}
void build(int st,int dr,int nod)
{
arb[nod].dr=dr;
arb[nod].st=st;
if(st==dr)
{
arb[nod].maxim=v[paths[nr].noduri[st]];
return;
}
int mijl=(st+dr)>>1;
build(st,mijl,nod<<1);
build(mijl+1,dr,(nod<<1)+1);
arb[nod].maxim=max(arb[nod<<1].maxim,arb[(nod<<1)+1].maxim);
}
void update(int unde,int val,int nod)
{
if(arb[nod].st==unde && arb[nod].dr==unde)
{
arb[nod].maxim=val;
return;
}
int mijl=(arb[nod].st+arb[nod].dr)>>1;
if(unde<=mijl)
update(unde,val,nod<<1);
else
update(unde,val,(nod<<1)+1);
arb[nod].maxim=max(arb[nod<<1].maxim,arb[(nod<<1)+1].maxim);
}
int query(int st,int dr,int nod)
{
//cout<<"query("<<st<<' '<<dr<<' '<<nod<<")\n";
if(arb[nod].st==st && arb[nod].dr==dr)
return arb[nod].maxim;
int mijl=(arb[nod].st+arb[nod].dr)>>1;
if(dr<=mijl)
return query(st,dr,nod<<1);
else if(st>mijl)
return query(st,dr,(nod<<1)+1);
else
return max(query(st,mijl,nod<<1),query(mijl+1,dr,(nod<<1)+1));
}
};
vector<arbint> arbori;
void dfs(int nod,int father)
{
for(vector<int>::iterator it=graf[nod].begin();it!=graf[nod].end();it++)
if(*it!=father)
{
deph[*it]=deph[nod]+1;
dfs(*it,nod);
gsize[nod]+=gsize[*it];
}
if(!gsize[nod])
{
path nou;
nou.father=0;
nou.noduri.push_back(nod);
what_path[nod]=paths.size();
paths.push_back(nou);
}
else
{
int maxim=0,cine=0;
for(vector<int>::iterator it=graf[nod].begin();it!=graf[nod].end();it++)
if(*it!=father && gsize[*it]>maxim)
maxim=gsize[*it],cine=*it;
what_path[nod]=what_path[cine];
paths[what_path[cine]].noduri.push_back(nod);
for(vector<int>::iterator it=graf[nod].begin();it!=graf[nod].end();it++)
if(*it!=father && *it!=cine)
paths[what_path[*it]].father=nod;
}
gsize[nod]++;
}
int lca(int x,int y)
{
//cout<<"lca("<<x<<","<<y<<")\n";
if(what_path[x]==what_path[y])
{
//cout<<"da"<<endl;
if(deph[x]>deph[y])
swap(x,y);
//cout<<arbori[what_path[x]].query(what_poz[x],what_poz[y],1)<<" OKOKOK!"<<endl;
return arbori[what_path[x]].query(what_poz[x],what_poz[y],1);
}
if(deph[paths[what_path[x]].father]<deph[paths[what_path[y]].father])
swap(x,y);
return max(arbori[what_path[x]].query(0,what_poz[x],1),lca(paths[what_path[x]].father,y));
}
int main()
{
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int n=0,m=0,a,b,i;
cin>>n>>m;
for(i=1;i<=n;i++)
cin>>v[i];
for(i=1;i<n;i++)
{
cin>>a>>b;
graf[a].push_back(b);
graf[b].push_back(a);
}
deph[1]=1;
dfs(1,0);
vector<path>::iterator it;
int j;
for(j=0,it=paths.begin();it!=paths.end();it++,j++)
{
reverse(it->noduri.begin(),it->noduri.end());
vector<int>::iterator it2;
for(it2=it->noduri.begin(),i=0;it2!=it->noduri.end();i++,it2++)
what_poz[*it2]=i;
arbint x(j);
arbori.push_back(x);
arbori[j].create(it->noduri.size());
arbori[j].build(0,it->noduri.size()-1,1);
}
bool tip;
for(i=0;i<m;i++)
{
cin>>tip>>a>>b;
if(tip)
cout<<lca(a,b)<<'\n';
else
arbori[what_path[a]].update(what_poz[a],b,1);
}
cin.close();
cout.close();
return 0;
}