#include <cstdio>
#include <vector>
#include <algorithm>
#include <vector>
#include <bitset>
#include <cmath>
#define Nmax 100005
#define INF 0x3f3f3f3f
using namespace std;
int N,Q,val[Nmax],weight[Nmax],height[Nmax],pozL[Nmax],care[Nmax];
int tata[Nmax],nrl = 1,pos,_newval,answer,A,B;
vector<int> G[Nmax];
bitset<Nmax> used,uzus;
vector<int> range[Nmax],lantz[Nmax];
class cmp{
public:
bool operator()(const int x,const int y)const
{
return weight[x] > weight[y];
}
};
void read()
{
scanf("%d%d",&N,&Q);
for(int i = 1; i <= N; ++i)
scanf("%d",&val[i]);
int a,b;
for(int i = 1; i < N; ++i)
{
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
}
void DFS(int k)
{
used[k] = 1;
for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
if(!used[*it])
{
height[*it] = height[k] + 1;
DFS(*it);
}
weight[k] = 1;
for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
weight[k] += weight[*it];
}
void descompune(int k)
{
used[k] = 1;
care[k] = nrl;
lantz[nrl].push_back(k);
for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
if(!used[*it])
{
if(!uzus[k])
{
uzus[k] = 1;
descompune(*it);
}
else
{
tata[++nrl] = k;
lantz[nrl].push_back(0);
descompune(*it);
}
}
}
class SegmentTree{
public:
void Build(int li,int lf,int pz,int linie)
{
if(li == lf)
{
range[linie][pz] = val[lantz[linie][li]];
return;
}
int m = li + ((lf-li)>>1);
Build(li,m,pz<<1,linie);
Build(m+1,lf,(pz<<1)|1,linie);
range[linie][pz] = max(range[linie][pz<<1],range[linie][(pz<<1)|1]);
}
void Update(int li,int lf,int pz,int linie)
{
if(li == lf)
{
range[linie][pz] = _newval;
return;
}
int m = li + ((lf-li)>>1);
if(pos <= m) Update(li,m,pz<<1,linie);
else Update(m+1,lf,(pz<<1)|1,linie);
range[linie][pz] = max(range[linie][pz<<1],range[linie][(pz<<1)|1]);
}
void Querry(int li,int lf,int pz,int line)
{
if(A <= li && lf <= B)
{
answer = max(answer,range[line][pz]);
return;
}
int m = li + ((lf-li)>>1);
if(A <= m) Querry(li,m,pz<<1,line);
if(m < B) Querry(m+1,lf,(pz<<1)|1,line);
}
}Aint;
void decompoz()
{
height[1] = 1;
DFS(1);
used = 0;lantz[1].push_back(0);
for(int i = 1; i <= N; ++i)
sort(G[i].begin(),G[i].end(),cmp());
descompune(1);
for(int i = 1; i <= N; ++i)
{
for(int j = 1; j <= (1 << ((int)(log2(lantz[i].size()))+1) ) + 1; ++j )
range[i].push_back(0);
}
for(int i = 1; i <= nrl; ++i)
for(int j = 1; j < lantz[i].size(); ++j)
pozL[lantz[i][j]] = j;
}
void make_tree()
{
for(int i = 1; i <= nrl; ++i)
Aint.Build(1,lantz[i].size()-1,1,i);
}
void solve()
{
int tip,a,b,lan,tasu;
for(int i = 1; i <= Q; ++i)
{
scanf("%d%d%d",&tip,&a,&b);
if(tip == 0)
{
_newval = b;
lan = care[a];
pos = pozL[a];
Aint.Update(1,lantz[lan].size()-1,1,lan);
}
else
{
if(height[A] < height[B])swap(A,B);
answer = -INF;
while(care[a] != care[b])
{
if(height[a] < height[b]) swap(a,b);
A = 1;
B = height[a];
Aint.Querry(1,lantz[care[a]].size()-1,1,care[A]);
a = tata[care[a]];
}
A = a;
B = b;
Aint.Querry(1,lantz[care[a]].size()-1,1,care[a]);
printf("%d\n",answer);
}
}
}
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
read();
decompoz();
make_tree();
solve();
return 0;
}