#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMAX = 1e5 + 5;
int n, q, depth[NMAX], where[NMAX];//where[i] - lantul unde se afla nodul i
vector <int> g[NMAX];
int values[NMAX];//valorile nodurilor
int weight[NMAX]; // greutatea fiecarui nod
int nrChains;
int pozChain[NMAX]; // pozitia nodului in lantul din care face parte
struct pathdecomp
{
int father;
vector <int> path;//retin lantul
}chains[NMAX];
inline void citire()
{
fin >> n >> q;
int i;
for(i = 1; i <= n; ++i)
fin >> values[i];
for(i = 1; i < n; ++i)
{
int a, b;
fin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
}
pair <int, int> maxSon[NMAX]; // weight-ul maxim al unui fiu al nodului i si nodul asociat maximului
//determin weight-ul
int calcWeight(int node, int d)
{
depth[node] = d;
weight[node] = 1;
for(auto &it: g[node])
{
if(weight[it] == 0)// daca nu e vizitat
{
weight[node] += calcWeight(it, d + 1);
if(maxSon[node].first < weight[it])
maxSon[node].first = weight[it], maxSon[node].second = it;
}
}
return weight[node];
}
bitset <NMAX> viz(0);
void createChains(int node, int chainNumber)
{
where[node] = chainNumber;
//indexare de la 1
if(chains[chainNumber].path.empty())
chains[chainNumber].path.push_back(0);
chains[chainNumber].path.push_back(node);
pozChain[node] = chains[chainNumber].path.size() - 1;
for(auto &it: g[node])
{
if(depth[it] < depth[node])
continue;
if(it == maxSon[node].second) // daca am gasit maximul
createChains(it, chainNumber);
else
{
++nrChains;
chains[nrChains].father = node;
createChains(it, nrChains);
}
}
}
vector < vector <int> > AINT; // AINT[i] - arborele de intervale asociat lantului i
void intAINT(int chainNumber, int node, int st, int dr)
{
if(st == dr)
AINT[chainNumber][node] = values[chains[chainNumber].path[st]];
else
{
int mij = (st + dr) / 2;
intAINT(chainNumber, 2 * node, st, mij);
intAINT(chainNumber, 2 * node + 1, mij + 1, dr);
AINT[chainNumber][node] = max(AINT[chainNumber][2 * node], AINT[chainNumber][2 * node + 1]);
}
}
inline void init_AINT()
{
int i;
AINT.resize(nrChains + 2);
for(i = 1; i <= nrChains; ++i)
{
AINT[i].resize(1ll << int(log2(chains[i].path.size()) + 2));
intAINT(i, 1, 1, chains[i].path.size() - 1);
}
}
inline void update_AINT(int chainNumber, int node, int st, int dr, int poz, int val)
{
if(st == dr && st == poz)
AINT[chainNumber][node] = val;
else
{
int mij = (st + dr) / 2;
if(poz <= mij)
update_AINT(chainNumber, 2 * node, st, mij, poz, val);
else update_AINT(chainNumber, 2 * node + 1, mij + 1, dr, poz, val);
AINT[chainNumber][node] = max(AINT[chainNumber][2 * node], AINT[chainNumber][2 * node + 1]);
}
}
int query_AINT(int chainNumber, int node, int st, int dr, int start, int stop)
{
if(start <= st && dr <= stop)
return AINT[chainNumber][node];
else
{
int mij = (st + dr) / 2, a1, a2;
a1 = a2 = INT_MIN;
if(start <= mij) // am o parte din interval in stangas
a1 = query_AINT(chainNumber, 2 * node, st, mij, start, stop);
if(stop > mij) // am o parte din interval in dreapta
a2 = query_AINT(chainNumber, 2 * node + 1, mij + 1, dr, start, stop);
return max(a1, a2);
}
}
int answerQuery(int x, int y)//y stramos al lui x
{
//sunt in acelasi lant
if(where[x] == where[y])
{
int aux = query_AINT(where[x], 1, 1, chains[where[x]].path.size() - 1, min(pozChain[x], pozChain[y]), max(pozChain[x], pozChain[y]));
return aux;
}
//daca nu este indeplinita conditia de stramos
if(depth[chains[where[x]].father] < depth[chains[where[y]].father])
swap(x, y);
int a1 = query_AINT(where[x], 1, 1, chains[where[x]].path.size() - 1, 1, pozChain[x]);
int a2 = answerQuery(chains[where[x]].father, y);
return max(a1, a2);
}
int main()
{
memset(depth, 0, sizeof depth);
memset(where, 0, sizeof where);
memset(weight, 0, sizeof weight);
memset(values, 0, sizeof values);
citire();
calcWeight(1, 1);
++nrChains;
chains[1].father = 0;
createChains(1, 1);
init_AINT();
int i;
int query_type, x, y;
for(int i = 1; i <= q; ++i)
{
fin >> query_type >> x >> y;
if(query_type == 0)//update in AINT, indicele x devine y
{
update_AINT(where[x], 1, 1, chains[where[x]].path.size() - 1, pozChain[x], y);
}
else
{
fout << answerQuery(x, y) << '\n';
}
}
return 0;
}