#include <bits/stdc++.h>
#define DIM 100010
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int N, M, numberLanturi;
int v[DIM], niv[DIM], w[DIM], lant[DIM];
int AINT[4 * DIM];
int lantTata[DIM], lantNiv[DIM], lantPoz[DIM], lantDim[DIM];
vector<int> L[DIM], Path[DIM];
bitset<DIM> viz;
inline void DFS(const int &node)
{
viz[node] = 1;
w[node] = 1; // "greutatea" subarborelui node
int weightNode = -1; // vecinul cel mai "greu"
bool leaf = true;
for(int i = 0; i < L[node].size(); i ++)
{
if(viz[ L[node][i] ] == 0)
{
leaf = false;
niv[ L[node][i] ] = niv[node] + 1;
DFS(L[node][i]);
w[node] += w[ L[node][i] ]; //cresc greutatea
if(weightNode == -1)
{
weightNode = L[node][i];
}
else
{
if(w[weightNode] < w[ L[node][i] ])
{
weightNode = L[node][i]; // actualizez cel mai "greu" vecin
}
}
}
}
if(leaf == true)
{
lant[node] = ++numberLanturi; // lantul incepe din frunza
lantDim[numberLanturi] = 1; // dimensiunea lantului
Path[numberLanturi].push_back(node); //drumul
return;
}
lant[node] = lant[weightNode];
++lantDim[ lant[node] ];
Path[ lant[node] ].push_back(node);
for(int i = 0; i < L[node].size(); i ++)
{
if(L[node][i] == weightNode || niv[ L[node][i] ] < niv[node])
{
continue;
}
lantTata[ lant[ L[node][i] ] ] = node; // tatal lantului lui L[node][i] este lantul lui node
lantNiv [ lant[ L[node][i] ] ] = niv[node]; // nivelul lantului lui L[node][i] este nivelul lui node
}
}
inline void build(const int& node, const int& left, const int &right, const int &decalaj, const int &nrLant)
{
if(left == right)
{
AINT[node + decalaj] = v[ Path[nrLant][left - 1] ]; // in frunza am valoarea nodului din lantul nrLant;
return;
}
int middle = (left + right) >> 1;
build(2 * node, left, middle, decalaj, nrLant);
build(2 * node + 1, middle + 1, right, decalaj, nrLant);
AINT[node + decalaj] = max( AINT[2 * node + decalaj], AINT[2 * node + 1 + decalaj] );
}
inline void update(const int& node, const int& left, const int &right, const int &poz, const int &val, const int &decalaj)
{
if(left == right)
{
AINT[node + decalaj] = val;
return;
}
int middle = (left + right) >> 1;
if(poz <= middle)
{
update(2 * node, left, middle, poz, val, decalaj);
}
else
{
update(2 * node + 1, middle + 1, right, poz, val, decalaj);
}
AINT[node + decalaj] = max( AINT[2 * node + decalaj], AINT[2 * node + 1 + decalaj] );
}
inline int query(const int &node, const int &left, const int &right, const int &posx, const int &posy, const int &decalaj)
{
if(posx <= left && right <= posy)
{
return AINT[node + decalaj];
}
int middle = (left + right) >> 1, solution = 0;
if(posx <= middle)
{
solution = max(solution, query(2 * node, left, middle, posx, posy, decalaj) );
}
if(middle < posy)
{
solution = max(solution, query(2 * node + 1, middle + 1, right, posx, posy, decalaj) );
}
return solution;
}
int main()
{
fin >> N >> M;
for(int i = 1; i <= N; i ++)
{
fin >> v[i];
}
for(int i = 1; i < N; i ++)
{
int a, b;
fin >> a >> b;
L[a].push_back(b);
L[b].push_back(a);
}
niv[1] = 1;
DFS(1);
for(int i = 1; i <= numberLanturi; i ++)
{
reverse(Path[i].begin(), Path[i].end()); // il sortam crescator dupa nivel, era sortat descrescator datorita actualizarii pe revenirea DFS-ului
if(i > 1)
{
lantPoz[i] = lantPoz[i - 1] + lantDim[i - 1] * 4; // la AINT am nevoie de 4 * dimensiune, asa ca voi decala lanturile la dreapta cu 4 * dimensiunea celui anterior
}
build(1, 1, lantDim[i], lantPoz[i], i); // build la left 1, right lantDim[i], lantul este decalat cu lantPoz[i], i-lea lant
}
for(int i = 1; i <= M; i ++)
{
int type, x , y;
fin >> type >> x >> y;
if(type == 0)
{
update(1, 1, lantDim[ lant[x] ], niv[x] - lantNiv[ lant[x] ], y, lantPoz[ lant[x] ]);
/// update la left 1, right dimensiunea lantului lui x, pozitia lui x in lant este niv[x] - lantNiv[ lant[x] ], valoare y, decalaj lantPoz[ lant[x] ]
}
else
{
int solution = 0;
while(1)
{
if(lant[x] == lant[y]) // x si y sunt in acelasi lant - cazul "fericit"
{
if(niv[x] > niv[y])
{
swap(x, y);
}
solution = max(solution, query(1, 1, lantDim[ lant[x] ], niv[x] - lantNiv[ lant[x] ], niv[y] - lantNiv[ lant[x] ], lantPoz[ lant[x] ]) );
/// query la 1, left 1 right lungimea lantului lui x si y, pozitia lui x, pozitia lui y, decalajul lantului lui x si y
break;
}
if(lantNiv[ lant[x] ] < lantNiv[ lant[y] ])
{
swap(x, y);
}
solution = max(solution, query(1, 1, lantDim[ lant[x] ], 1, niv[x] - lantNiv[ lant[x] ], lantPoz[ lant[x] ]));
/// query la 1, left 1, right dimensiunea lantului lui x, inceputul lantului, pozitia lui x in lant, decalaj;
x = lantTata[ lant[x] ]; // x = tatal lantului lui x;
}
fout << solution << '\n';
}
}
return 0;
}