#include <fstream>
#include <vector>
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int val [100100];
vector < vector < int > > gr (100100);
vector < bool > used (100100);
vector < vector < int > > arb (100100);
vector < vector < int > > Arb (100100);
vector < int > tata_lant (100100);
vector < int > lant (100100);
vector < int > lv (100100);
vector < int > pos (100100);
int cont = 0;
int dfs(int root){
used[root] = true;
int MAX = 0;
int go = 0;
int last = 0;
for (auto &x : gr[root]){
if (used[x]){
last = x;
continue;
}
lv[x] = lv[root] + 1;
int val = dfs(x);
if (MAX < val){
MAX = val;
go = x;
}
}
if (go == 0){
cont++;
arb[cont].push_back(root);
lant[root] = cont;
pos[root] = 1;
}
else{
arb[lant[go]].push_back(root);
lant[root] = lant[go];
pos[root] = arb[lant[root]].size();
for (auto &x : gr[root]){
if (x == last || x == go){
continue;
}
tata_lant [lant[x]] = root;
}
}
return MAX + 1;
}
void Resize(){
for (int i=1; i<=cont; i++){
Arb[i].resize(arb[i].size() * 4);
}
}
void Update (int nod , int st , int dr , int poz , int val , int ARB){
if (st == dr){
Arb[ARB][nod] = val;
return;
}
int mij = st + dr;
mij /= 2;
if (mij >= poz){
Update(nod * 2 , st , mij , poz , val , ARB);
}
else{
Update(nod * 2 + 1 , mij + 1 , dr , poz , val , ARB);
}
Arb[ARB][nod] = max ( Arb[ARB][nod * 2] , Arb[ARB][nod * 2 + 1] );
}
void Querry (int nod , int st , int dr , int MIN , int MAX , int ARB , int &maxx){
if (MIN <= st && MAX >= dr){
maxx = max ( maxx , Arb[ARB][nod] );
return;
}
int mij = st + dr;
mij /= 2;
if (mij >= MIN){
Querry (nod * 2 , st , mij , MIN , MAX , ARB , maxx);
}
if (mij < MAX){
Querry (nod * 2 + 1, mij + 1 , dr , MIN , MAX , ARB , maxx);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n , m;
cin>>n>>m;
for (int i=1; i<=n; i++){
cin>>val[i];
}
for (int i=1; i<n; i++){
int a , b;
cin>>a>>b;
gr[a].push_back(b);
gr[b].push_back(a);
}
dfs(1);
/*for (int i=1; i<=cont; i++){
cout<<i<<" : ";
for (auto &x : arb[i]){
cout<<x<<" ";
}
cout<<'\n';
cout<<"nod tata -> "<<tata_lant[i]<<'\n';
cout<<"lant tata -> "<<lant[tata_lant[i]]<<'\n';
cout<<"lv -> "<<lv[arb[i][arb[i].size() - 1]]<<'\n';
cout<<'\n';
}
cout<<"------------------------------------"<<'\n'<<'\n';*/
Resize();
for (int i=1; i<=n; i++){
//cout<<i<<" : "<<val[i]<<" "<<lant[i]<<" "<<pos[i]<<" "<<lv[i]<<'\n';
Update (1 , 1 , arb[lant[i]].size() , pos[i] , val[i] , lant[i]);
}
for (int i=1; i<=m; i++){
int test , x , y;
cin>>test>>x>>y;
if (test == 0){
val[x] = y;
Update (1 , 1 , arb[lant[x]].size() , pos[x] , val[x] , lant[x]);
}
else{
int maxx = 0;
while ( lant[x] != lant[y] ){
int lv_x = lv [ arb [lant[x]] [arb [ lant[x] ].size() - 1 ]];
int lv_y = lv [ arb [lant[y]] [arb [ lant[y] ].size() - 1 ]];
if (lv_x > lv_y){
Querry(1, 1 , arb[lant[x]].size() , pos[x] , arb[lant[x]].size() , lant[x] , maxx);
x = tata_lant[lant[x]];
}
else{
Querry(1, 1 , arb[lant[y]].size() , pos[y] , arb[lant[y]].size() , lant[y] , maxx);
y = tata_lant[lant[y]];
}
}
Querry(1, 1 , arb[lant[x]].size() , min(pos[x] , pos[y]) , max(pos[x] , pos[y]) , lant[x] , maxx);
cout<<maxx<<'\n';
}
}
return 0;
}