#include <cstring>
#include <fstream>
#include <vector>
#include <cmath>
using namespace std;
class InputReader {
public:
InputReader() {}
InputReader(const char *file_name) {
input_file = fopen(file_name, "r");
cursor = 0;
fread(buffer, SIZE, 1, input_file);
}
inline InputReader &operator >>(int &n) {
while (buffer[cursor] < '0' || buffer[cursor] > '9') {
advance();
}
n = 0;
while ('0' <= buffer[cursor] && buffer[cursor] <= '9') {
n = n * 10 + buffer[cursor] - '0';
advance();
}
return *this;
}
private:
FILE *input_file;
static const int SIZE = 1 << 17;
int cursor;
char buffer[SIZE];
inline void advance() {
++ cursor;
if (cursor == SIZE) {
cursor = 0;
fread(buffer, SIZE, 1, input_file);
}
}
};
InputReader cin ("heavypath.in");
ofstream cout ("heavypath.out");
const int MaxN = 100005, TreeSize = (1 << 19);
vector <int> G[MaxN];
int n, m, treeTop;
int v[MaxN], depth[MaxN], son[MaxN], Tree[TreeSize], treePos[MaxN], father[MaxN], subtree[MaxN];
bool used[MaxN];
class Path {
public:
int pathSt, depth, lf, rg;
Path(int _pathSt = 0, int _depth = 1, int _lf = 0, int _rg = 0) {
pathSt = _pathSt;
depth = _depth;
lf = _lf;
rg = _rg;
}
};
Path nullPath = Path();
Path* pathOf[MaxN];
vector <Path*> pathList;
void Dfs(int node = 1, int level = 1) {
used[node] = true;
depth[node] = level;
++subtree[node];
if (G[node].size() == 1 and node != 1) {
pathOf[node] = new Path;
pathOf[node]->pathSt = node;
pathList.push_back(pathOf[node]);
return;
}
Path *bestPath = &nullPath;
int bestSubtree = 0;
for (auto nxt: G[node]) {
if (used[nxt]) {
continue;
}
father[nxt] = node;
Dfs(nxt, level + 1);
subtree[node] += subtree[nxt];
if (subtree[nxt] > bestSubtree) {
bestPath = pathOf[nxt];
bestSubtree = subtree[nxt];
}
}
son[node] = bestPath->pathSt;
pathOf[node] = bestPath;
++pathOf[node]->depth;
pathOf[node]->pathSt = node;
}
inline void BuildNode(int &node, int &lf, int &rg) {
node = max(lf, rg);
}
void Update(int CurrTree[], int pos, int val, int lf, int rg, int node = 1) {
if (lf == rg) {
CurrTree[node] = val;
return;
}
int lfSon = 2 * node;
int rgSon = 2 * node + 1;
int med = (lf + rg) / 2;
if (pos <= med) {
Update(CurrTree, pos, val, lf, med, lfSon);
}
else {
Update(CurrTree, pos, val, med + 1, rg, rgSon);
}
BuildNode(CurrTree[node], CurrTree[lfSon], CurrTree[rgSon]);
}
void Query(int &ans, int CurrTree[], int srLf, int srRg, int lf, int rg, int node = 1) {
if (srLf <= lf and srRg >= rg) {
ans = max(ans, CurrTree[node]);
return;
}
if (lf > srRg or rg < srLf) {
return;
}
int lfSon = 2 * node;
int rgSon = 2 * node + 1;
int med = (lf + rg) / 2;
Query(ans, CurrTree, srLf, srRg, lf, med, lfSon);
Query(ans, CurrTree, srLf, srRg, med + 1, rg, rgSon);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> v[i];
}
for (int i = 1; i <= n - 1; ++i) {
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
memset(son, -1, sizeof son);
Dfs();
for (auto &it: pathList) {
int node = it->pathSt;
while (node != -1) {
treePos[node] = depth[node] - depth[it->pathSt] + 1;
node = son[node];
}
it->lf = treeTop + 1;
it->rg = log2(it->depth);
it->rg += (1 << it->rg) < it->depth;
it->rg = 1 << (it->rg);
treeTop += it->rg * 2;
}
// for (int i = 1; i <= n; ++i) {
// cout << pathOf[i]->pathSt << '\n';
// }
// cout << '\n';
for (int i = 1; i <= n; ++i) {
Update(Tree + pathOf[i]->lf, treePos[i], v[i], 1, pathOf[i]->rg);
}
for (int i = 1; i <= m; ++i) {
int type, a, b;
cin >> type >> a >> b;
//Update
if (type == 0) {
int currLf = pathOf[a]->lf;
int currRg = pathOf[a]->rg;
Update(Tree + currLf, treePos[a], b, 1, currRg);
}
//Query
else {
auto ita = pathOf[a];
auto itb = pathOf[b];
int ans = 0;
while (ita != itb) {
if (depth[ita->pathSt] > depth[itb->pathSt]) {
Query(ans, Tree + ita->lf, 1, depth[a] - depth[ita->pathSt] + 1, 1, ita->rg);
a = father[ita->pathSt];
ita = pathOf[a];
}
else {
Query(ans, Tree + itb->lf, 1, depth[b] - depth[itb->pathSt] + 1, 1, itb->rg);
b = father[itb->pathSt];
itb = pathOf[b];
}
}
if (depth[a] > depth[b]) {
swap(a, b);
}
Query(ans, Tree + ita->lf, depth[a] - depth[ita->pathSt] + 1, depth[b] - depth[itb->pathSt] + 1, 1, ita->rg);
cout << ans <<'\n';
}
}
return 0;
}