#include <iostream>
#include <fstream>
#include <vector>
#define vt vector
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMAX = 1e5;
int n, q;
vt <int> adj[NMAX + 1];
int v[NMAX + 1];
int lvl[NMAX + 1];
int parent[NMAX + 1];
int sub[NMAX + 1];
int heavy[NMAX + 1];
void explore(int node, int par){
parent[node] = par;
lvl[node] = lvl[par] + 1;
sub[node] = 1;
for(int vec : adj[node]){
if(vec != par){
explore(vec, node);
sub[node] += sub[vec];
}
}
for(int vec : adj[node]){
if(vec != par){
if(sub[vec] > sub[heavy[node]]){
heavy[node] = vec;
}
}
}
}
int ID = 0;
int Id[NMAX + 1];
int head[NMAX + 1];
int Time = 0;
int lin[NMAX + 1];
int pos[NMAX + 1];
void heavy_first(int node, int par){
++Time;
lin[Time] = node;
pos[node] = Time;
if(heavy[par] != node){
head[++ID] = node;
Id[node] = ID;
}else{
Id[node] = Id[par];
}
if(heavy[node] != 0){
heavy_first(heavy[node], node);
}
for(int vec : adj[node]){
if(vec != par && vec != heavy[node]){
heavy_first(vec, node);
}
}
}
namespace AINT{
int aint[4 * NMAX + 1];
void build(int node, int l, int r){
if(l == r){
aint[node] = v[lin[l]];
return;
}
int mid = (l + r) / 2;
build(2 * node, l, mid);
build(2 * node + 1, mid + 1, r);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
void update(int node, int l, int r, int pos, int val){
if(l == r){
aint[node] = val;
return;
}
int mid = (l + r) / 2;
if(pos <= mid){
update(2 * node, l, mid, pos, val);
}else{
update(2 * node + 1, mid + 1, r, pos, val);
}
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
int query(int node, int l, int r, int ql, int qr){
if(ql <= l && r <= qr){
return aint[node];
}
int mid = (l + r) / 2, ans = 0;
if(ql <= mid){
ans = max(ans, query(2 * node, l, mid, ql, qr));
}
if(mid + 1 <= qr){
ans = max(ans, query(2 * node + 1, mid + 1, r, ql, qr));
}
return ans;
}
}
int heavy_query(int a, int b){
int ans = 0;
cout << "====================\n";
while(Id[a] != Id[b]){
if(lvl[head[Id[a]]] > lvl[head[Id[b]]]){
//cout << "->> " << pos[a] << ' ' << pos[head[Id[a]]] << endl;
ans = max(ans, AINT::query(1, 1, n, pos[head[Id[a]]], pos[a]));
a = parent[head[Id[a]]];
}else{
// cout << "-> " << pos[b] << ' ' << pos[head[Id[b]]] << endl;
// cout << "+ " << b << ' ' << head[Id[b]] << endl;
ans = max(ans, AINT::query(1, 1, n, pos[head[Id[b]]], pos[b]));
b = parent[head[Id[b]]];
}
}
ans = max(ans, AINT::query(1, 1, n, min(pos[a], pos[b]), max(pos[a], pos[b])));
return ans;
}
void solve(){
fin >> n >> q;
for(int i = 1; i <= n; i++){
fin >> v[i];
}
for(int i = 1; i <= n - 1; i++){
int a, b;
fin >> a >> b;
adj[a].pb(b);
adj[b].pb(a);
}
explore(1, 0);
heavy_first(1, 0);
AINT::build(1, 1, n);
// for(int i = 1; i <= n; i++){
// cout << ">> " << i << ' ' << pos[i] << ' ' << Id[i] << ' ' << head[Id[i]] << '\n';
// }
// for(int i = 1; i <= n; i++){
// cout << lin[i] << ' ';
// }
// cout << '\n';
while(q--){
int type;
fin >> type;
if(type == 0){
int node, val;
fin >> node >> val;
AINT::update(1, 1, n, pos[node], val);
}else{
int x, y;
fin >> x >> y;
fout << heavy_query(x, y) << '\n';
}
}
}
int main(){
int T;
// fin >> T;
T = 1;
while(T--){
solve();
}
return 0;
}