#include <bits/stdc++.h>
#define OP_UPDATE 0
#define OP_QUERY 1
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMAX = 1e5;
struct AINT {
struct node {
int maxx = 0;
};
vector<node>aint;
AINT() {
aint.resize(4 * NMAX + 3);
}
void update(int nod, int st, int dr, int l, int r, int val) {
if(l > dr || r < st || dr < st || r < l)
return;
if(st == l && dr == r) {
aint[nod].maxx = val;
} else {
int mid = (st + dr) / 2;
update(nod * 2, st, mid, l, min(mid, r), val);
update(nod * 2 + 1, mid + 1, dr, max(mid + 1, l), r, val);
aint[nod].maxx = max(aint[nod * 2].maxx, aint[nod * 2 + 1].maxx);
}
}
int query(int nod, int st, int dr, int l, int r) {
if(l > dr || r < st || dr < st || r < l)
return 0;
if(st == l && dr == r) {
return aint[nod].maxx;
} else {
int mid = (st + dr) / 2;
return max(query(nod * 2, st, mid, l, min(mid, r)), query(nod * 2 + 1, mid + 1, dr, max(mid + 1, l), r));
}
}
};
AINT aint;
struct Node {
int val = 0, parent = 0, lvl = 0, heavy = 0, head = 0, poz = 0;
};
vector<vector<int>> edge;
int t, n, q, x, y;
struct heavyLightDecomp {
vector<int> decomp;
int curpoz = 0;
int dfsCalc(int nod, int tata, vector<Node>& nodes) {
int dsize = 1, maxChild = 0;
Node& curNode = nodes[nod];
curNode.parent = tata;
curNode.lvl = nodes[tata].lvl + 1;
for(int child : edge[nod]) {
if(child == tata)
continue;
int childSize = dfsCalc(child, nod, nodes);
if(childSize > maxChild) {
maxChild = childSize;
curNode.heavy = child;
}
dsize += childSize;
}
return dsize;
}
void dfsDecomp(int nod, int head, vector<Node>& nodes) {
Node& curNode = nodes[nod];
curNode.head = head;
curNode.poz = ++curpoz;
decomp.push_back(nod);
if(curNode.heavy != 0)
dfsDecomp(curNode.heavy, head, nodes);
for(int child : edge[nod]) {
if(child == curNode.heavy || child == curNode.parent)
continue;
dfsDecomp(child, child, nodes);
}
}
void dfs(int nod, vector<Node>& nodes, int tata = 0) {
fout << nod << " parent: " << nodes[nod].parent << " lvl: " << nodes[nod].lvl << " head: " << nodes[nod].head << " heavy: " << nodes[nod].heavy << " poz: " << nodes[nod].poz << "\n";
for(int child : edge[nod]) {
if(child == tata)
continue;
dfs(child, nodes, nod);
}
}
};
heavyLightDecomp heavylight;
vector<Node> nodes;
int query(int x, int y) {
int ans = 0;
while(nodes[x].head != nodes[y].head) {
if(nodes[nodes[x].head].lvl > nodes[nodes[y].head].lvl)
swap(x, y);
ans = max(ans, aint.query(1, 1, n, nodes[nodes[y].head].poz, nodes[y].poz));
y = nodes[nodes[y].head].parent;
}
if(nodes[x].lvl > nodes[y].lvl)
swap(x, y);
ans = max(ans, aint.query(1,1,n,nodes[x].lvl, nodes[y].lvl));
return ans;
}
void solve() {
heavylight.dfsCalc(1, 0, nodes);
heavylight.dfsDecomp(1, 1, nodes);
// heavylight.dfs(1, nodes);
for(int i = 1; i <= n; i++)
aint.update(1, 1, n, i, i, nodes[i].val);
for(int i = 1; i <= q; i++) {
fin >> t >> x >> y;
if(t == OP_UPDATE)
aint.update(1, 1, n, nodes[x].poz, nodes[x].poz, y);
else if(t == OP_QUERY)
fout << query(x, y) << "\n";
}
}
void read() {
fin >> n >> q;
edge.resize(n + 1);
nodes.resize(n + 1);
heavylight.decomp.resize(n + 1);
for(int i = 1; i <= n; i++)
fin >> nodes[i].val;
for(int i = 1; i <= n - 1; i++) {
fin >> x >> y;
edge[x].push_back(y);
edge[y].push_back(x);
}
}
int main() {
// iostream::sync_with_stdio(false);
// fin.tie(NULL);
read();
solve();
return 0;
}