#include <cstdio>
#include <vector>
#include <bitset>
#include <algorithm>
#include <cmath>
#define Nmax 100005
#define INF 0x3f3f3f3f
using namespace std;
int N,Q,valori[Nmax],nrl = 1;
bitset<Nmax> used;
vector<int> G[Nmax];
vector<int> lantz[Nmax]; /// lantz[i] -> lantzul cu nr de ordine i
vector<int> range[Nmax];
int greutate[Nmax]; /// greutate[i] -> numarul de descendenti ai lui i
int adancime[Nmax]; /// adancime[i] -> adancimea nodului i plecand din 1
int care[Nmax]; /// care[i] -> in care lantz se afla nodul i
int tata_lantz[Nmax]; /// tata_lantz[i] -> de ce nod se leaga lantzul din care face parte i
int pozitie_nod[Nmax]; /// pozitie_nod[i] -> locul in care se afla nodul in latzul din care face parte
#define DIM 500000
char buff[DIM];
int poZ=DIM-1;
void citeste(int &numar)
{
numar = 0;
while (buff[poZ] < '0' || buff[poZ] > '9')
if (++poZ == DIM)
fread(buff,1,DIM,stdin),poZ=0;
while ('0'<=buff[poZ] && buff[poZ]<='9')
{
numar = numar*10 + buff[poZ] - '0';
if (++poZ == DIM)
fread(buff,1,DIM,stdin),poZ=0;
}
}
class cmp{
public:
bool operator()(const int x,const int y)const
{
return greutate[x] > greutate[y];
}
};
void read()
{
citeste(N),citeste(Q);///scanf("%d%d",&N,&Q);
int a,b;
for(int i = 1; i <= N; ++i) citeste(valori[i]);///scanf("%d",valori+i);
for(int i = 1; i < N; ++i){
citeste(a),citeste(b);///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])
{
adancime[*it] = adancime[k] + 1;
DFS(*it);
}
for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
greutate[k] += greutate[*it];
++greutate[k];
}
void descomp(int k)
{
care[k] = nrl;
lantz[nrl].push_back(k); /// incepem descompunerea
pozitie_nod[k] = lantz[nrl].size()-1;
used[k] = 1;
for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
if(!used[*it])
{
if(lantz[nrl].size() == 1)
tata_lantz[nrl] = k;
descomp(*it);
}
if(G[k].size() == 1 && k != 1){
++ nrl; /// sunt intr-o frunzulitzaa
lantz[nrl].push_back(0); /// jmenarim indexarea
}
}
void decomposition()
{
DFS(1);
for(int i = 1; i <= N; ++i)
sort(G[i].begin(),G[i].end(),cmp());
adancime[1] = 1;
used = 0; lantz[1].push_back(0);
descomp(1); -- nrl;
for(int i = 1; i <= nrl; ++i)
for(int j = 0; j <= (1<<((int)log2(lantz[i].size())+ 1)) + 1 ; ++j)
range[i].push_back(0);
}
int line,A,B,pos,_newX,answer;
class SegmentTree{
public:
void Build(int li,int lf,int pz)
{
if(li == lf)
{
range[line][pz] = valori[lantz[line][li]];
return;
}
int m = li + ((lf-li)>>1);
Build(li,m,pz<<1);
Build(m+1,lf,(pz<<1)|1);
range[line][pz] = max(range[line][pz<<1],range[line][(pz<<1)|1]);
}
void Update(int li,int lf,int pz)
{
if(li == lf)
{
range[line][pz] = _newX;
return;
}
int m = li + ((lf-li)>>1);
if(pos <= m) Update(li,m,pz<<1);
else Update(m+1,lf,(pz<<1)|1);
range[line][pz] = max(range[line][pz<<1],range[line][(pz<<1)|1]);
}
void Querry(int li,int lf,int pz)
{
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);
if(m < B) Querry(m+1,lf,(pz<<1)|1);
}
void Make()
{
for(int i = 1; i <= nrl; ++i)
{
line = i;
Build(1,lantz[i].size()-1,1);
}
}
}Aint;
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
read();
decomposition();
Aint.Make();
int typ,x,y;
for(int i = 1; i <= Q; ++i)
{
citeste(typ),citeste(x),citeste(y);
///scanf("%d%d%d",&typ,&x,&y);
if(typ == 0)
{
_newX = y;
pos = pozitie_nod[x];
line = care[x];
Aint.Update(1,lantz[line].size()-1,1);
}
else
{
answer = -INF;
while(care[x] != care[y])
{
if(adancime[tata_lantz[care[x]]] < adancime[tata_lantz[care[y]]]) swap(x,y);
line = care[x];
A = 1;
B = pozitie_nod[x];
Aint.Querry(1,lantz[line].size()-1,1);
x = tata_lantz[care[x]];
}
A = pozitie_nod[x];
B = pozitie_nod[y];
line = care[x];
if(A > B) swap(A,B);
Aint.Querry(1,lantz[line].size()-1,1);
printf("%d\n",answer);
}
}
return 0;
}