#include <cstring>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
const int SIZE = 100002;
int N, M;
int A[SIZE], Son[SIZE], T[SIZE];
vector<int> V[SIZE], Lant[SIZE];
int where[SIZE], whpos[SIZE], sL;
int in[SIZE], out[SIZE], sE;
bool heavy[SIZE], isheavy[SIZE];
bool is_str(int nod1, int nod2)
{
return in[nod1] <= in[nod2] && out[nod1] >= out[nod2];
}
int LCA(int nod1, int nod2) // TO DO
{
if (is_str(nod1, nod2))
return nod1;
if (is_str(nod2, nod1))
return nod2;
while (!is_str(Lant[where[nod1]].back(), nod2))
nod1 = T[Lant[where[nod1]].back()];
if (is_str(nod1, nod2))
return nod1;
int step, nowLCA;
for (step = 1; (step << 1) < Lant[where[nod1]].size(); step <<= 1);
for (nowLCA = -1; step; step >>= 1)
if (nowLCA + step < Lant[where[nod1]].size() && !is_str(Lant[where[nod1]][nowLCA + step], nod2))
nowLCA += step;
++nowLCA;
return Lant[where[nod1]][nowLCA];
}
int qPos, Val, result, I1, I2;
int AINT[SIZE * 4];
void update(int nod, int s1, int s2)
{
if (s1 == s2)
{
AINT[nod] = Val;
return;
}
int mid = (s1 + s2) >> 1;
if (qPos <= mid) update(nod * 2, s1, mid);
else update(nod * 2 + 1, mid + 1, s2);
AINT[nod] = max(AINT[nod * 2], AINT[nod * 2 + 1]);
}
void query(int nod, int s1, int s2)
{
if (I1 <= s1 && s2 <= I2)
{
result = max(result, AINT[nod]);
return;
}
int mid = (s1 + s2) >> 1;
if (I1 <= mid) query(nod * 2, s1, mid);
if (I2 > mid) query(nod * 2 + 1, mid + 1, s2);
}
void preDfs(int x)
{
Son[x] = 1;
for (vector<int>::iterator it = V[x].begin(); it != V[x].end(); ++it)
if (*it != T[x])
{
in[*it] = ++sE;
T[*it] = x;
preDfs(*it);
Son[x] += Son[*it];
out[*it] = ++sE;
}
}
void heavy_light(int x)
{
for (vector<int>::iterator it = V[x].begin(); it != V[x].end(); ++it)
if (*it != T[x] && Son[*it] >= Son[x] / 2)
{
heavy[*it] = true;
isheavy[x] = true;
break;
}
for (vector<int>::iterator it = V[x].begin(); it != V[x].end(); ++it)
if (*it != T[x])
heavy_light(*it);
if (!isheavy[x] && where[x] == 0)
{
int now = x;
++sL;
while (true)
{
++qPos;
Val = A[now];
update(1, 1, N);
Lant[sL].push_back(now);
where[now] = sL;
whpos[now] = qPos;
if (!heavy[now]) break;
now = T[now];
}
}
}
int getResult(int now, int nodLCA)
{
int maxnow = 0;
while (LCA(Lant[where[now]].back(), nodLCA) == nodLCA)
{
result = 0;
I1 = whpos[now], I2 = whpos[Lant[where[now]].back()];
query(1, 1, N);
maxnow = max(maxnow, result);
if (Lant[where[now]].back() == nodLCA)
{
now = nodLCA;
break;
}
now = T[Lant[where[now]].back()];
}
if (now != nodLCA)
{
result = 0;
I1 = whpos[now], I2 = whpos[nodLCA];
query(1, 1, N);
maxnow = max(maxnow, result);
}
else
maxnow = max(maxnow, A[now]);
return maxnow;
}
int main()
{
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
fin >> N >> M;
for (int i = 1; i <= N; ++i)
fin >> A[i];
for (int i = 1, nod1, nod2; i < N; ++i)
{
fin >> nod1 >> nod2;
V[nod1].push_back(nod2);
V[nod2].push_back(nod1);
}
in[1] = ++sE;
preDfs(1);
heavy_light(1);
out[1] = ++sE;
for (int i = 1, t, x, y; i <= M; ++i)
{
fin >> t >> x >> y;
if (t == 0)
{
qPos = whpos[x];
Val = y;
update(1, 1, N);
A[x] = y;
}
else
{
int nodLCA = LCA(x, y), maxnow = 0;
maxnow = max(getResult(x, nodLCA), getResult(y, nodLCA));
fout << maxnow << '\n';
}
}
fin.close();
fout.close();
}