#include <bits/stdc++.h>
using namespace std;
ofstream fout("heavypath.out");
ifstream fin("heavypath.in");
const int NMax = 100010;
int niv[NMax];
int sub[NMax];
int path[NMax];
vector<int> P[NMax];
vector<int> G[NMax];
int parent[NMax];
int val[NMax];
int k, n, m, x, y, o;
vector<int> T[NMax];
int pos[NMax];
void makePaths(int node, int prev, int level){
int maxi = 0;
int connect = 0;
niv[node] = level;
for(int i = 0; i < G[node].size(); i++){
int next = G[node][i];
if(next == prev) continue;
makePaths(next, node, level + 1);
if(sub[next] > maxi){
maxi = sub[next];
connect = next;
}
}
if(!maxi){
P[++k].push_back(node);
path[node] = k;
sub[node] = 1;
return;
}
P[path[connect]].push_back(node);
path[node] = path[connect];
sub[node] = sub[connect];
for(int i = 0; i < G[node].size(); i++){
int next = G[node][i];
if(next == prev) continue;
if(next != connect){
parent[path[next]] = node;
}
}
}
void reversePaths()
{
for(int i = 1; i <= k; i++){
reverse(P[i].begin(), P[i].end());
}
}
void update(vector<int> &t, int pos, int st, int dr, int val, int node){
if(st == dr){
t[pos] = val;
return;
}
int mid = (st + dr) / 2;
if(node <= mid) update(t, pos * 2, st, mid, val, node);
else update(t, pos * 2 + 1, mid + 1, dr, val, node);
t[pos] = max(t[pos * 2], t[pos * 2 + 1]);
}
int maxim(vector<int> &t, int st, int dr, int l, int r, int pos){
if(st==l && dr==r)
{
return t[pos];
}
int mij = (l+r)/2, nr1 = 0, nr2 = 0;
if(st <= mij) nr1 = maxim(t, st, min(dr, mij), l, mij, pos * 2);
if(dr > mij) nr2 = maxim(t, max(mij+1, st), dr, mij + 1, r, pos * 2 + 1);
return max(nr1,nr2);
}
void makeTrees(){
for(int i = 1; i <= k; i++){
for(int j = 0; j < P[i].size(); j++){
T[i].resize(4*P[i].size() + 1);
update(T[i], 1, 1, P[i].size(), val[P[i][j]], j + 1);
pos[P[i][j]] = j + 1;
}
}
}
int solve2(int x, int y){
int rez = val[x];
while(x != y){
if(niv[parent[path[x]]] < niv[parent[path[y]]] || parent[path[x]] == 0) swap(x, y);
if(path[x] == path[y]){
rez = max(rez, maxim(T[path[x]], min(pos[x], pos[y]), max(pos[x],pos[y]), 1, P[path[x]].size(), 1));
y = x;
}
else{
rez = max(rez, maxim(T[path[x]], 1, pos[x], 1, P[path[x]].size(), 1));
x = parent[path[x]];
}
}
return rez;
}
void query(){
for(int i = 1; i <= m; i++){
fin >> o >> x >> y;
if(o == 0){
val[x] = y;
update(T[path[x]], 1, 1, P[path[x]].size(), y, pos[x]);
}
else{
fout << solve2(x, y) << '\n';
}
}
}
int main()
{
fin >> n >> m;
for(int i = 1; i <= n; i++) fin >> val[i];
for(int i = 1; i < n; i++){
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
makePaths(1, 0, 0);
reversePaths();
makeTrees();
query();
return 0;
}