#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <algorithm>
namespace segment_tree {
template <typename Tinfo>
class DefaultCombiner {
public:
Tinfo operator()(Tinfo const &lsh, Tinfo const &rsh) {
return std::max(lsh, rsh);
}
};
template <typename Tinfo, typename Combiner = DefaultCombiner<Tinfo> >
class SegmentTree {
private:
public:
int size_;
std::vector<Tinfo> tree_;
/*
* Function that compute an aggregate, such as max/min/sum,
* of the interval [lsh, rsh].
*/
Combiner combine_;
public:
// Default Constructor
SegmentTree();
// Constructor
SegmentTree(std::vector<Tinfo> array);
// Destructor
~SegmentTree();
/*
* Build a segment tree from array.
*
* @param array // given array to build.
*/
void build(std::vector<Tinfo> array);
/**
* Update value of element from position p.
*
* @param p, value // Set value at position p.
*/
void update(int p, int value);
/**
* Get an aggregate on interval [lsh, rsh).
*
* @param lsh, rsh // left and right bounds of the interval.
* @return an aggregate on interval [lsh, rsh).
*/
Tinfo query(int lsh, int rsh);
/*
* Get size of array used.
*
* @return size of array used.
*/
int size();
};
template <typename Tinfo, typename Combiner>
SegmentTree<Tinfo, Combiner>::SegmentTree(): size_(0) {}
template <typename Tinfo, typename Combiner>
SegmentTree<Tinfo, Combiner>::SegmentTree(std::vector<Tinfo> array): size_(array.size()), tree_(2 * array.size()) {
for (int i = 0; i < size_; ++i) {
tree_[size_ + i] = array[i];
}
for (int i = size_ - 1; i > 0; --i) {
tree_[i] = combine_(tree_[i << 1], tree_[ i<< 1 | 1]);
}
}
template <typename Tinfo, typename Combiner>
SegmentTree<Tinfo, Combiner>::~SegmentTree() {}
template <typename Tinfo, typename Combiner>
void SegmentTree<Tinfo, Combiner>::build(std::vector<Tinfo> array) {
size_ = array.size();
tree_.resize(2 * size_);
for (int i = 0; i < size_; ++i) {
tree_[size_ + i] = array[i];
}
for (int i = size_ - 1; i > 0; --i) {
tree_[i] = combine_(tree_[i << 1], tree_[ i<< 1 | 1]);
}
}
template <typename Tinfo, typename Combiner>
void SegmentTree<Tinfo, Combiner>::update(int p, int value) {
for (tree_[p += size_] = value, p >>= 1; p > 0; p >>= 1) {
tree_[p] = combine_(tree_[p << 1], tree_[p << 1 | 1]);
}
}
template <typename Tinfo, typename Combiner>
Tinfo SegmentTree<Tinfo, Combiner>::query(int lsh, int rsh) {
bool used_lsh = false, used_rsh = false;
Tinfo ret_lsh, ret_rsh;
for (lsh += size_, rsh += size_; lsh < rsh; lsh >>= 1, rsh >>= 1) {
if (lsh & 1) {
if (used_lsh) {
ret_lsh = combine_(ret_lsh, tree_[lsh++]);
} else {
ret_lsh = tree_[lsh++];
used_lsh = true;
}
}
if (rsh & 1) {
if (used_rsh) {
ret_rsh = combine_(tree_[--rsh], ret_rsh);
} else {
ret_rsh = tree_[--rsh];
used_rsh = true;
}
}
}
if (used_lsh && used_rsh) {
return combine_(ret_lsh, ret_rsh);
} else {
return (used_lsh)? ret_lsh: ret_rsh;
}
}
template <typename Tinfo, typename Combiner>
int SegmentTree<Tinfo, Combiner>::size() {
return size_;
}
} // namespace segment_tree
namespace tree_decomposition_lca {
template <typename Tinfo>
class DefaultCombiner {
public:
Tinfo operator()(Tinfo const &lsh, Tinfo const &rsh) {
return std::max(lsh, rsh);
}
};
template <typename Tinfo, typename Combiner = DefaultCombiner<Tinfo> >
class TreeDecompositionLCA {
private:
public:
struct Node {
std::vector<int> neighbors_;
};
int size_;
/*
* Function that compute an aggregate, such as max/min/sum,
* of the interval [lsh, rsh].
*/
Combiner combine_;
std::vector<Node> node_; // each node has a list of neighbours
std::vector<Tinfo> cost_; // information of each node
std::vector<int> depth_; // depth of each node
std::vector<int> parent_; // parent of each node
/**
* Depth-first search for father vector build.
*
* @param node - Current node in search.
*/
void dfs(int node);
public:
// Constructor
TreeDecompositionLCA(int size);
// Destructor
~TreeDecompositionLCA();
/**
* Access information associated to existing node.
*
* @param node Node of whose information will be returned.
* @return reference to information associated to the given node.
*/
Tinfo& operator[](int node);
/**
* Adds an edge between two existing nodes.
*
* @param src Source node of the edge to be added.
* @param dst Destination node of the edge to be added.
*/
void add_edge(int src, int dst);
/**
* Gets the tree size.
*
* @return Number of nodes in the tree.
*/
int size();
/**
* Build tree decomposition.
*/
void build();
/**
* Update value of node.
*
* @param node, value // Set value of node.
*/
void update(int node, Tinfo value);
/**
* Returns an aggregate, such as max/min/sum,
* of the weights of the nodes or edges on the path
* from node src to node dst.
*
* @param src Source node.
* @param dst Destination node.
* @return max/min/sum of the weights of the nodes or
* edges on the path from node src to node dst.
*/
Tinfo query(int src, int dst);
};
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::dfs(int node) {
for (auto son: node_[node].neighbors_) {
if (!depth_[son]) { // unvisited son
depth_[son] = depth_[node] + 1;
parent_[son] = node;
dfs(son);
}
}
}
template <typename Tinfo, typename Combiner>
TreeDecompositionLCA<Tinfo, Combiner>::TreeDecompositionLCA(int size): size_(size), node_(size),
cost_(size), depth_(size, 0), parent_(size) {}
template <typename Tinfo, typename Combiner>
TreeDecompositionLCA<Tinfo, Combiner>::~TreeDecompositionLCA() {}
template <typename Tinfo, typename Combiner>
Tinfo& TreeDecompositionLCA<Tinfo, Combiner>::operator[](int node) {
return cost_[node];
}
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::add_edge(int src, int dst) {
node_[src].neighbors_.push_back(dst);
node_[dst].neighbors_.push_back(src);
}
template <typename Tinfo, typename Combiner>
int TreeDecompositionLCA<Tinfo, Combiner>::size() {
return size_;
}
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::build() {
depth_[0] = 1;
dfs(0);
parent_[0] = -1;
}
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::update(int node, Tinfo value) {
cost_[node] = value;
}
template <typename Tinfo, typename Combiner>
Tinfo TreeDecompositionLCA<Tinfo, Combiner>::query(int src, int dst) {
std::vector<int> path_src;
std::vector<int> path_dst;
Tinfo ret;
while (src != dst) {
if (depth_[src] > depth_[dst]) {
path_src.push_back(src);
src = parent_[src];
} else {
path_dst.push_back(dst);
dst = parent_[dst];
}
}
// get full path from src to dst
path_src.push_back(src);
for (auto it = path_dst.rbegin(); it != path_dst.rend(); ++it) {
path_src.push_back(*it);
}
ret = cost_[path_src[0]];
for (unsigned int i = 1; i < path_src.size(); ++i) {
ret = combine_(ret, cost_[path_src[i]]);
}
return ret;
}
} // namespace tree_decomposition_lca
std::ifstream fin("heavypath.in");
std::ofstream fout("heavypath.out");
int main() {
int N, M, val, t, x, y;
fin >> N >> M;
tree_decomposition_lca::TreeDecompositionLCA<int> treeDecomp(N);
for (int i = 0; i < N; ++i) {
fin >> treeDecomp[i];
}
for (int i = 1; i < N; ++i) {
fin >> x >> y;
treeDecomp.add_edge(x - 1, y - 1);
}
treeDecomp.build();
for (int i = 0; i < M; ++i) {
fin >> t >> x >> y;
if (t) {
fout << treeDecomp.query(x - 1, y - 1) << '\n';
} else {
treeDecomp.update(x - 1, y);
}
}
return 0;
}