#include <fstream>
#include <vector>
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
const int NMAX = 1e5;
int N, Q, value[NMAX + 2];
vector <int> g[NMAX + 2];
int w[NMAX + 2], h[NMAX + 2], dad[NMAX + 2];
void dfs(int node, int parent) {
w[node] = 1;
dad[node] = parent;
for(int son : g[node]) {
if(son != parent) {
h[son] = h[node] + 1;
dfs(son, node);
w[node] += w[son];
}
}
}
vector <int> order;
int pos[NMAX + 2], head[NMAX + 2];
void dfs2(int node) {
order.push_back(node);
pos[node] = (int)order.size();
if((int)g[node].size() == 1 && node != 1) {
return ;
}
int heavySon = g[node][0];
if(heavySon == dad[node]) {
heavySon = g[node][1];
}
for(int son : g[node]) {
if(son != dad[node]) {
if(w[son] > w[heavySon]) {
heavySon = son;
}
}
}
head[heavySon] = head[node];
dfs2(heavySon);
for(int son : g[node]) {
if(son != dad[node] && son != heavySon) {
dfs2(son);
}
}
}
struct SegmentTree{
int v[4 * NMAX];
void Update(int node, int st, int dr, int pos, int val) {
if(st == dr) {
v[node] = val;
return ;
}
int mid = (st + dr) >> 1;
if(pos <= mid) {
Update(2 * node, st, mid, pos, val);
} else {
Update(2 * node + 1, mid + 1, dr, pos, val);
}
v[node] = max(v[2 * node], v[2 * node + 1]);
}
int Query(int node, int st, int dr, int L, int R) {
if(R < st || dr < L) {
return 0;
}
if(L <= st && dr <= R) {
return v[node];
}
int mid = (st + dr) >> 1;
return max(Query(2 * node, st, mid, L, R),
Query(2 * node + 1, mid + 1, dr, L, R));
}
};
SegmentTree st;
int Query(int x, int y) {
if(head[x] == head[y]) {
///we are on the same heavy chain
if(pos[x] > pos[y]) {
swap(x, y);
}
return st.Query(1, 1, N, pos[x], pos[y]);
}
if(h[head[x]] < h[head[y]]) {
swap(x, y);
}
///we move x one chain up
int ans1 = st.Query(1, 1, N, pos[head[x]], pos[x]);
x = dad[head[x]];
return max(ans1, Query(x, y));
}
int main() {
cin >> N >> Q;
for(int i = 1; i <= N; i++) {
cin >> value[i];
}
for(int i = 1; i < N; i++) {
int x, y;
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1, 0);
for(int i = 1; i <= N; i++) {
head[i] = i;
}
dfs2(1);
for(int i = 1; i <= N; i++) {
st.Update(1, 1, N, pos[i], value[i]);
}
for(int i = 1; i <= Q; i++) {
int t, x, y;
cin >> t >> x >> y;
if(t == 0) {
st.Update(1, 1, N, pos[x], y);
} else {
cout << Query(x, y) << '\n';
}
}
return 0;
}