#include <vector>
#include <utility>
#include <cstdlib>
#include <exception>
template<typename T, typename TFunc>
class IntervalTree
{
private:
struct Node
{
size_t a, b;
Node *parent, *left, *right;
T val;
};
public:
IntervalTree(const std::vector<T>* _cont, TFunc _functor) :
functor(std::move(_functor)),
initialCont(_cont),
root(nullptr),
leaves(_cont->size(), nullptr)
{
ConstructTree(0, _cont->size() - 1, &root);
initialCont = nullptr;
}
~IntervalTree()
{
DestructDownwards(&root);
}
void UpdateValue(size_t index, const T& val)
{
leaves[index]->val = val;
UpdateUpwards(leaves[index]);
}
T GetRange(size_t a, size_t b) const
{
if (a > b)
{
size_t aux = a;
a = b;
b = aux;
}
return GetRange(leaves[a], a, b);
}
private:
void ConstructTree(const size_t a, const size_t b, Node** node)
{
if (a <= b)
{
(*node) = new Node;
(*node)->parent = (*node)->right = (*node)->left = nullptr;
(*node)->a = a;
(*node)->b = b;
if (a == b)
{
(*node)->val = initialCont->at(a);
leaves[a] = (*node);
}
else
{
const size_t mean = (a + b) / 2;
{
Node* left;
ConstructTree(a, mean, &left);
(*node)->left = left;
(*node)->left->parent = (*node);
}
{
Node* right;
ConstructTree(mean + 1, b, &right);
(*node)->right = right;
(*node)->right->parent = (*node);
}
UpdateNodeValue(*node);
}
}
else
{
(*node) = nullptr;
}
}
void DestructDownwards(Node** node)
{
if ((*node) != nullptr)
{
DestructDownwards(&((*node)->left));
DestructDownwards(&((*node)->right));
delete (*node);
(*node) = nullptr;
}
}
void UpdateNodeValue(Node* node)
{
if (node != nullptr)
{
if ((node->left != nullptr) && (node->right != nullptr))
{
node->val = functor(node->left->val, node->right->val);
}
else
{
if ((node->left != nullptr) && (node->right == nullptr))
{
node->val = node->left->val;
}
else
{
if ((node->left == nullptr) && (node->right != nullptr))
{
node->val = node->right->val;
}
}
}
}
}
void UpdateUpwards(Node* node)
{
if (node != nullptr)
{
UpdateNodeValue(node);
UpdateUpwards(node->parent);
}
}
T GetRange(Node* node, size_t a, size_t b) const
{
if (node->b < b)
{
T* ptrRightVal = nullptr;
if (((node->parent->left == node) && (node->a != a)) || (node->a < a))
{
if (node->right->a >= a)
{
ptrRightVal = &(node->right->val);
}
}
if (ptrRightVal != nullptr)
{
return functor(*ptrRightVal, GetRange(node->parent, a, b));
}
else
{
return GetRange(node->parent, a, b);
}
}
else
{
if (node->b == b)
{
if (node->a >= a)
{
return node->val;
}
else
{
return GetRange(node->right, a, b);
}
}
else
{
if (node->left->b >= b)
{
return GetRange(node->left, a, b);
}
else
{
if (node->left->a >= a)
{
return functor(node->left->val, GetRange(node->right, a, b));
}
else
{
return GetRange(node->right, a, b);
}
}
}
}
}
private:
TFunc functor;
private:
const std::vector<T>* initialCont;
private:
Node* root;
std::vector<Node*> leaves;
};
#include <vector>
#include <exception>
#include <cstdint>
template<typename T, typename TFunc>
class RQ
{
private:
static int IntLog2(uint64_t val)
{
int res = 0;
while (val != 0)
{
val /= 2;
++res;
}
return res - 1;
}
public:
RQ(const std::vector<T>& _cont, const TFunc& _functor) :
functor(_functor),
rangeVal((size_t) (IntLog2((uint64_t) _cont.size()) + 1ULL))
{
rangeVal[0] = std::vector<T>(_cont.size());
for (size_t i = 0; i < _cont.size(); ++i)
{
rangeVal[0][i] = _cont[i];
}
for (size_t exp = 1; exp < rangeVal.size(); ++exp)
{
{
size_t maI = 0;
while ((maI + (1ULL << exp) - 1) < rangeVal[0].size())
{
++maI;
}
rangeVal[exp] = std::vector<T>(maI);
}
for (size_t i = 0; i < rangeVal[exp].size(); ++i)
{
rangeVal[exp][i] = functor(rangeVal[exp - 1][i], rangeVal[exp - 1][i + (1ULL << (exp - 1))]);
}
}
}
T GetRange(size_t a, size_t b) const
{
if (a > b)
{
size_t aux = a;
a = b;
b = aux;
}
const size_t elemCount = b - a + 1;
const size_t exp = IntLog2(elemCount);
return functor(rangeVal[exp][a], rangeVal[exp][b - (1ULL << exp) + 1]);
}
private:
TFunc functor;
std::vector<std::vector<T>> rangeVal;
};
#define MAX_N 100000
#include <fstream>
#include <vector>
#include <queue>
#include <memory>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int n, m, LVL[MAX_N + 1], T[MAX_N + 1];
vector<int> G[MAX_N + 1];
vector<int> Vals;
const auto fctorRq = [] (int node1, int node2) { return (LVL[node1] < LVL[node2]) ? node1 : node2; };
using RMQ = RQ<int, decltype(fctorRq)>;
const auto fctorIt = [] (int a, int b) { return (a > b) ? a : b; };
using IT = IntervalTree<int, decltype(fctorIt)>;
int P[MAX_N + 1];
RMQ* rmqLca;
struct Path
{
shared_ptr<int> bottom = nullptr, top = nullptr;
shared_ptr<vector<int>> temp = nullptr;
shared_ptr<IT> it = nullptr;
};
Path Pth[MAX_N + 1];
void LevelGraph(int node);
void EulerTour(vector<int>& out);
int Lca(int node1, int node2);
void CreatePaths();
int GetNodePosition(int node);
int GetMax(int node1, int node2);
int main()
{
fin >> n >> m;
Vals = vector<int>(n + 1);
for (int i = 1; i <= n; ++i)
{
fin >> Vals[i];
}
for (int i = 1; i < n; ++i)
{
int a, b;
fin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
LevelGraph(1);
{
vector<int> eulerTour;
EulerTour(eulerTour);
rmqLca = new RMQ(eulerTour, fctorRq);
}
CreatePaths();
Vals.clear();
for (int i = 0; i < m; ++i)
{
int t;
fin >> t;
if (t == 0)
{
int x;
int y;
fin >> x >> y;
int posX = GetNodePosition(x);
Pth[x].it->UpdateValue(posX, y);
}
else
{
int x, y;
fin >> x >> y;
fout << GetMax(x, y) << '\n';
}
}
delete rmqLca;
rmqLca = nullptr;
fin.close();
fout.close();
return 0;
}
void LevelGraph(int node)
{
for (int i = 0; i < n; ++i)
{
T[i] = LVL[i] = 0;
}
queue<int> Q;
Q.push(node);
LVL[node] = 1;
while (!Q.empty())
{
int front = Q.front();
Q.pop();
for (int adjNode : G[front])
{
if (LVL[adjNode] == 0)
{
T[adjNode] = front;
LVL[adjNode] = LVL[front] + 1;
Q.push(adjNode);
}
}
}
}
int glP;
void EulerTour(int node, int fath, vector<int>& out)
{
out[++glP] = node;
P[node] = glP;
for (int adjNode : G[node])
{
if (adjNode != fath)
{
EulerTour(adjNode, node, out);
out[++glP] = node;
}
}
}
void EulerTour(vector<int>& out)
{
out = vector<int>(2 * n - 1);
glP = -1;
EulerTour(1, 0, out);
}
int Lca(int node1, int node2)
{
return rmqLca->GetRange(P[node1], P[node2]);
}
void FinishPath(int node)
{
vector<int> tempVals(Pth[node].temp->size());
for (size_t i = 0; i < tempVals.size(); ++i)
{
tempVals[i] = Vals[Pth[node].temp->at(i)];
}
shared_ptr<IT> pIt(new IT(&tempVals, fctorIt));
for (int nodeInPath : (*Pth[node].temp))
{
Pth[nodeInPath].it = pIt;
}
Pth[node].temp->clear();
}
int CreatePaths(int node, int fath)
{
int resNode = 0;
int ma = 0;
int sum = 1;
for (int adjNode : G[node])
{
if (adjNode != fath)
{
int res = CreatePaths(adjNode, node);
sum += res;
if (ma < res)
{
resNode = adjNode;
ma = res;
}
}
}
if (resNode == 0)
{
Pth[node].bottom = shared_ptr<int>(new int(node));
Pth[node].top = shared_ptr<int>(new int(node));
Pth[node].temp = shared_ptr<vector<int>>(new vector<int>());
Pth[node].temp->push_back(node);
}
else
{
Pth[node].bottom = Pth[resNode].bottom;
Pth[node].top = Pth[resNode].top;
Pth[node].temp = Pth[resNode].temp;
(*Pth[node].top) = node;
Pth[node].temp->push_back(node);
for (int adjNode : G[node])
{
if ((adjNode != fath) && (adjNode != resNode))
{
FinishPath(adjNode);
}
}
}
return sum;
}
void CreatePaths()
{
CreatePaths(1, 0);
FinishPath(1);
}
int GetNodePosition(int node)
{
return LVL[*Pth[node].bottom] - LVL[node];
}
int GetMaxUpwards(int node, int upperNode)
{
if (Pth[node].it.get() != Pth[upperNode].it.get())
{
const int ma = Pth[node].it->GetRange(GetNodePosition(node), GetNodePosition(*Pth[node].top));
return fctorIt(ma, GetMaxUpwards(T[*Pth[node].top], upperNode));
}
else
{
return Pth[node].it->GetRange(GetNodePosition(node), GetNodePosition(upperNode));
}
}
int GetMax(int node1, int node2)
{
const int lca = Lca(node1, node2);
const int ma1 = GetMaxUpwards(node1, lca);
const int ma2 = GetMaxUpwards(node2, lca);
return fctorIt(ma1, ma2);
}