#include <bits/stdc++.h>
using namespace std;
const int N_MAX = 100002;
const int M_MAX = 100002;
int n, m;
int val[N_MAX];
vector <int> edges[N_MAX];
int heavySon[N_MAX];
int parent[N_MAX];
int subSize[N_MAX];
bool visited[N_MAX];
vector <int> paths[N_MAX];
int cntPaths;
int pathIndex[N_MAX];
int pos[N_MAX];
short int pathLevel[N_MAX];
void dfs (int node)
{
visited[node] = true;
subSize[node] = 1;
int maxSize = 0;
for(int u : edges[node])
if(visited[u] == false)
{
parent[u] = node;
dfs(u);
subSize[node] += subSize[u];
if(subSize[u] > maxSize)
{
maxSize = subSize[u];
heavySon[node] = u;
}
}
}
void heavy (int node)
{
visited[node] = true;
pathIndex[node] = cntPaths;
pos[node] = paths[cntPaths].size();
paths[cntPaths].push_back(node);
if(heavySon[node] != 0)
heavy(heavySon[node]);
for(int u : edges[node])
if(visited[u] == false && u != heavySon[node])
{
cntPaths++;
pathLevel[cntPaths] = pathLevel[pathIndex[node]] + 1;
heavy(u);
}
}
vector <int> aint[N_MAX];
void build (int index, int node, int l, int r)
{
if(l == r)
{
aint[index][node] = val[paths[index][l]];
return;
}
int mid = (l + r) / 2, lson = (node << 1), rson = (lson | 1);
build(index, lson, l, mid);
build(index, rson, mid + 1, r);
aint[index][node] = max(aint[index][lson], aint[index][rson]);
}
void update (int index, int node, int l, int r, int upos, int uval)
{
if(l == r)
{
aint[index][node] = uval;
return;
}
int mid = (l + r) / 2, lson = (node << 1), rson = (lson | 1);
if(upos <= mid)
update(index, lson, l, mid, upos, uval);
else
update(index, rson, mid + 1, r, upos, uval);
aint[index][node] = max(aint[index][lson], aint[index][rson]);
}
int query (int index, int node, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr)
return aint[index][node];
int mid = (l + r) / 2, lson = (node << 1), rson = (lson | 1);
int val1 = 0, val2 = 0;
if(ql <= mid)
val1 = query(index, lson, l, mid, ql, qr);
if(mid + 1 <= qr)
val2 = query(index, rson, mid + 1, r, ql, qr);
return max(val1, val2);
}
int main()
{
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
fin >> n >> m;
for(int i = 1; i <= n; i++)
fin >> val[i];
for(int i = 1; i < n; i++)
{
int u, v;
fin >> u >> v;
edges[u].push_back(v);
edges[v].push_back(u);
}
dfs(1);
memset(visited, false, sizeof(visited));
cntPaths = 1;
heavy(1);
for(int i = 1; i <= cntPaths; i++)
{
aint[i].resize(4 * paths[i].size());
build(i, 1, 0, paths[i].size() - 1);
}
while(m--)
{
int op;
fin >> op;
if(op == 0)
{
int node, uval;
fin >> node >> uval;
update(pathIndex[node], 1, 0, paths[pathIndex[node]].size() - 1, pos[node], uval);
}
else
{
int u, v;
fin >> u >> v;
int uPath = pathIndex[u];
int vPath = pathIndex[v];
int answer = 0;
if(uPath == vPath)
answer = query(uPath, 1, 0, paths[uPath].size() - 1, min(pos[u], pos[v]), max(pos[u], pos[v]));
else
{
answer = max(answer, query(vPath, 1, 0, paths[vPath].size() - 1, 0, pos[v]));
answer = max(answer, query(uPath, 1, 0, paths[uPath].size() - 1, 0, pos[u]));
}
while(uPath != vPath)
{
if(pathLevel[uPath] < pathLevel[vPath])
{
v = parent[paths[vPath][0]];
vPath = pathIndex[v];
if(uPath == vPath)
answer = max(answer, query(uPath, 1, 0, paths[uPath].size() - 1, min(pos[u], pos[v]), max(pos[u], pos[v])));
else
answer = max(answer, query(vPath, 1, 0, paths[vPath].size() - 1, 0, pos[v]));
}
else
{
u = parent[paths[uPath][0]];
uPath = pathIndex[u];
if(uPath == vPath)
answer = max(answer, query(uPath, 1, 0, paths[uPath].size() - 1, min(pos[u], pos[v]), max(pos[u], pos[v])));
else
answer = max(answer, query(uPath, 1, 0, paths[uPath].size() - 1, 0, pos[u]));
}
}
fout << answer << "\n";
}
}
return 0;
}