#include <fstream>
#include <vector>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
#define DIM 100000
int n, q, lant, id;
int v[DIM + 5];
int w[DIM + 5]; //cati descendenti are nodul i.
int poz[DIM + 5];
int tata[DIM + 5];
int level[DIM + 5];
int chain[DIM + 5]; //din ce lant face parte nodul i;
int first[DIM + 5]; //primul nod din fiecare lant;
int Sonmax[DIM + 5]; //fiul care are cei mai multi descendenti.
int tree[4 * DIM + 5];
int size_chain[DIM + 5]; //lungimea lantului actual.
vector <int> G[DIM + 5];
static inline void Update_tree(int st, int dr, int nod, int poz, int val) {
if(st == dr)
tree[nod] = val;
else {
int mid = (st + dr) >> 1;
if(poz <= mid)
Update_tree(st, mid, nod * 2, poz, val);
else Update_tree(mid + 1, dr, nod * 2 + 1, poz, val);
tree[nod] = max(tree[nod * 2], tree[nod * 2 + 1]);
}
}
static inline int Query_tree(int st, int dr, int nod, int left, int right) {
if(left <= st && dr <= right)
return tree[nod];
int mid = (st + dr) >> 1;
int max1 = 0, max2 = 0;
if(left <= mid)
max1 = Query_tree(st, mid, nod * 2, left, right);
if(mid < right)
max2 = Query_tree(mid + 1, dr, nod * 2 + 1, left, right);
return max(max1, max2);
}
static inline void dfs(int nod, int t) {
tata[nod] = t;
Sonmax[nod] = -1;
w[nod] = 1; //el insusi.
level[nod] = level[t] + 1;
for(auto e : G[nod])
if(e != t) {
dfs(e, nod);
if(Sonmax[nod] == -1 || w[Sonmax[nod]] < w[Sonmax[e]])
Sonmax[nod] = e; //fiul care are cei mai multi descendenti.
w[nod] += w[e];
}
}
static inline void Split(int nod) {
chain[nod] = lant;
poz[nod] = ++id;
size_chain[lant]++;
if(Sonmax[nod] == -1) //daca e frunza;
return;
Split(Sonmax[nod]);
for(auto e : G[nod])
if(e != tata[nod] && e != Sonmax[nod]) {
lant++;
first[lant] = e;
Split(e);
}
}
static inline void Heavy_path() {
dfs(1, 0);
first[1] = 1;
lant = 1;
Split(1);
for(int i = 1; i <= n; i++)
Update_tree(1, n, 1, poz[i], v[i]);
}
static inline int Query(int x, int y) {
if(chain[x] == chain[y])
return Query_tree(1, n, 1, min(poz[x], poz[y]), max(poz[x], poz[y]));
if(level[first[chain[x]]] < level[first[chain[y]]])
swap(x, y);
int ans = Query_tree(1, n, 1, poz[first[chain[x]]], poz[x]);
return max(ans, Query(tata[first[chain[x]]], y));
}
int main() {
fin.tie(0), fout.tie(0);
fin >> n >> q;
for(int i = 1; i <= n; i++)
fin >> v[i];
for(int i = 1, x, y; i < n; i++) {
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
Heavy_path();
for(int i = 1, tip, x, y; i <= q; i++) {
fin >> tip >> x >> y;
if(tip == 0)
Update_tree(1, n, 1, poz[x], y);
else fout << Query(x, y) << '\n';
}
return 0;
}