#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <cstdlib>
#define ll long long
using namespace std;
struct SegTree {
vector<int> aint;
void init(int n, const vector<int> &path, const vector<int> &v) {
aint.resize(4 * n + 5, 0);
buildtree(1, 1, n, v, path);
}
void buildtree(int node, int le, int ri, const vector<int> &v, const vector<int> &path) {
if(le == ri)
aint[node] = v[path[le]];
else {
int mid = (le + ri) / 2;
buildtree(node * 2, le, mid, v, path);
buildtree(node * 2 + 1, mid + 1, ri, v, path);
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
}
void update(int pos, int val, int node, int le, int ri) {
if(le == ri)
aint[node] = val;
else {
int mid = (le + ri) / 2;
if(pos <= mid)
update(pos, val, node * 2, le, mid);
else
update(pos, val, node * 2 + 1, mid + 1, ri);
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
}
int query(int from, int to, int node, int le, int ri) {
if(from <= le && ri <= to)
return aint[node];
else {
int mid = (le + ri) / 2;
int ans = 0;
if(from <= mid)
ans = max(ans, query(from, to, node * 2, le, mid));
if(mid < to)
ans = max(ans, query(from, to, node * 2 + 1, mid + 1, ri));
return ans;
}
}
};
struct HeavyPath {
vector<vector<int>> g;
int n, npaths;
vector<int> whichpath, h, dim, father;
vector<vector<int>> path;
vector<int> pos, boss;
vector<SegTree> aint;
HeavyPath(int _n, vector<vector<int>> &_g, vector<int> &v) {
n = _n;
g = _g;
npaths = 0;
whichpath.resize(n + 1, 0);
h.resize(n + 1, 0);
dim.resize(n + 1, 0);
father.resize(n + 1, 0);
h[1] = 1;
dfs(1, 0);
pos.resize(n + 1, 0);
boss.resize(npaths + 1, 0);
path.resize(npaths + 1, vector<int> (1, 0));
computepaths(1, 0);
aint.resize(npaths + 1);
for(int i = 1; i <= npaths; i ++)
aint[i].init(path[i].size() - 1, path[i], v);
exit(0);
}
void dfs(int node, int dad) {
father[node] = dad;
dim[node] = 1;
int mx = 0, from = 0;
for(auto it : g[node]) {
if(it == dad)
continue;
h[it] = h[node] + 1;
dfs(it, node);
dim[node] += dim[it];
if(dim[it] > mx) {
mx = dim[it];
from = it;
}
}
if(mx == 0) {
npaths ++;
whichpath[node] = npaths;
} else {
whichpath[node] = whichpath[from];
}
}
int update(int node, int val) {
aint[whichpath[node]].update(pos[node], val, 1, 1, path[whichpath[node]].size() - 1);
}
int query(int x, int y) {
int ans = 0;
while(whichpath[x] != whichpath[y]) {
if(h[boss[whichpath[x]]] < h[boss[whichpath[y]]])
swap(x, y);
ans = max(ans, aint[whichpath[x]].query(pos[x], pos[boss[whichpath[x]]], 1, 1, path[whichpath[x]].size() - 1));
x = father[boss[whichpath[x]]];
}
/// x si y sunt pe acelasi lant
if(pos[x] > pos[y])
swap(x, y);
ans = max(ans, aint[whichpath[x]].query(pos[x], pos[y], 1, 1, path[whichpath[x]].size() - 1));
return ans;
}
void computepaths(int node, int dad) {
for(auto it : g[node]) {
if(it == dad)
continue;
computepaths(it, node);
}
pos[node] = path[whichpath[node]].size();
path[whichpath[node]].push_back(node);
boss[whichpath[node]] = node;
}
};
int main() {
ifstream in("heavypath.in");
ofstream out("heavypath.out");
int n, q;
in >> n >> q;
vector<int> v(n + 1, 0);
for(int i = 1; i <= n; i ++)
in >> v[i];
vector<vector<int>> g(n + 1);
for(int i = 1; i < n; i ++) {
int x, y;
in >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
HeavyPath ans(n, g, v);
while(q --) {
int t, x, y;
in >> t >> x >> y;
if(t == 0) {
ans.update(x, y);
} else if(t == 1) {
out << ans.query(x, y) << "\n";
}
}
return 0;
}