#include <bits/stdc++.h>
using namespace std;
const long long NR = 1e5 + 1;
const int oo = 1e9;
int n, m, aIntCounter = -1;
vector<int> d, p, lvl, aIntPos, weight, aIntChain, parent;
vector<vector<int>> v, aInt, tree;
void updateSegTree(int chain, int nod, int st, int dr, int pos, int val) {
if (st == dr) {
tree[chain][nod] = val;
return;
}
int mid = (st + dr) / 2;
if (pos <= mid) {
updateSegTree(chain, nod << 1, st, mid, pos, val);
} else {
updateSegTree(chain, nod << 1 | 1, mid + 1, dr, pos, val);
}
tree[chain][nod] = max(tree[chain][nod << 1], tree[chain][nod << 1 | 1]);
}
void buildSegTree() {
for (int i = 0; i <= aIntCounter; ++i) {
tree[i].resize((aInt[i].size() + 1) * 4 + 5, 0);
for (int j = 0; j < aInt[i].size(); ++j) {
updateSegTree(i, 1, 1, (int) aInt[i].size(), j + 1, d[aInt[i][j]]);
}
}
}
int querySegTree(int chain, int nod, int st, int dr, int a, int b) {
if (a <= st && dr <= b) {
return tree[chain][nod];
}
int mid = (st + dr) >> 1, leftMax = 0, rightMax = 0;
if (a <= mid) {
leftMax = querySegTree(chain, nod << 1, st, mid, a, b);
}
if (mid < b) {
rightMax = querySegTree(chain, nod << 1 | 1, mid + 1, dr, a, b);
}
return max(leftMax, rightMax);
}
void dfs(int nod, int prt) {
parent[nod] = prt;
lvl[nod] = 1 + lvl[prt];
weight[nod] = 1;
int heaviest = -1, bestWeight = -1;
for (auto it : v[nod]) {
if (it == prt) {
continue;
}
dfs(it, nod);
weight[nod] += weight[it];
if (weight[it] > bestWeight) {
bestWeight = weight[it];
heaviest = it;
}
}
if (heaviest == -1) {
++aIntCounter;
aInt[aIntCounter].emplace_back(nod);
aIntPos[nod] = (int) aInt[aIntCounter].size() - 1;
aIntChain[nod] = aIntCounter;
} else {
aInt[aIntChain[heaviest]].emplace_back(nod);
aIntPos[nod] = (int) aInt[aIntChain[heaviest]].size() - 1;
aIntChain[nod] = aIntChain[heaviest];
}
}
int getMax(int chain, int st, int dr) {
return querySegTree(chain, 1, 1, (int) aInt[chain].size(), st, dr);
}
int findMaximum(int x, int y) {
int maximum = -oo;
while (aIntChain[x] != aIntChain[y]) {
if (lvl[parent[aInt[aIntChain[y]].back()]] > lvl[parent[aInt[aIntChain[x]].back()]]) {
swap(x, y);
}
maximum = max(maximum, getMax(aIntChain[x], aIntPos[x] + 1, (int) aInt[aIntChain[x]].size()));
x = parent[aInt[aIntChain[x]].back()];
}
return max(maximum, getMax(aIntChain[x], min(aIntPos[x], aIntPos[y]) + 1, max(aIntPos[x], aIntPos[y]) + 1));
}
signed main() {
ifstream in("heavypath.in");
ofstream out("heavypath.out");
ios::sync_with_stdio(false);
in.tie();
int x, y, t;
in >> n >> m;
d.resize(n + 1, 0);
parent.resize(n + 1, 0);
p.resize(n + 1, 0);
lvl.resize(n + 1, 0);
aIntPos.resize(n + 1, 0);
weight.resize(n + 1, 0);
aIntChain.resize(n + 1, 0);
v.resize(n + 1, vector<int>());
aInt.resize(n + 1, vector<int>());
tree.resize(n + 1, vector<int>());
for (int i = 1; i <= n; ++i) {
in >> d[i];
}
for (int i = 1; i < n; ++i) {
in >> x >> y;
v[x].emplace_back(y);
v[y].emplace_back(x);
}
dfs(1, 0);
buildSegTree();
for (int i = 1; i <= m; ++i) {
in >> t >> x >> y;
if (t == 0) {
updateSegTree(aIntChain[x], 1, 1, (int) aInt[aIntChain[x]].size(), aIntPos[x] + 1, y);
} else {
out << findMaximum(x, y) << '\n';
}
}
in.close();
out.close();
return 0;
}