#include <cstdio>
#include <algorithm>
#include <vector>
#include <climits>
using namespace std;
vector<int> value; // value[k] -> the value of the k'th node.
class SegmentTree{
public:
SegmentTree() = default;
void Build(const vector<int>& elem)
{
data_.resize(elem.size() * 4 + 1);
size_ = elem.size();
Build_(0, size_-1, 0, elem);
}
void Update(int index, int newValue)
{
Update_(0, size_-1, 0, index, newValue);
}
int Query(int A, int B)
{
int answer = numeric_limits<int>::min();
Query_(0, size_-1, 0, A, B, &answer);
return answer;
}
private:
void Build_(int li, int lf, int pz, const vector<int>& elem)
{
if (li == lf) {
data_[pz] = value[elem[li]];
return;
}
int m = li + ((lf-li)>>1);
Build_(li, m, (pz<<1)|1, elem);
Build_(m+1, lf, (pz+1)<<1, elem);
data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
}
void Update_(int li, int lf, int pz, int index, int newValue)
{
if (li == lf) {
data_[pz] = newValue;
return;
}
int m = li + ((lf-li)>>1);
if (index <= m)
Update_(li, m, (pz<<1)|1, index, newValue);
else
Update_(m+1, lf, (pz+1)<<1, index, newValue);
data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
}
void Query_(int li, int lf, int pz, int A, int B, int* answer)
{
if (A <= li && lf <= B) {
*answer = max(*answer, data_[pz]);
return;
}
int m = li + ((lf - li) >> 1);
if (A <= m)
Query_(li, m, (pz<<1)|1, A, B, answer);
if (B > m)
Query_(m+1, lf, (pz+1)<<1, A, B, answer);
}
vector<int> data_;
int size_;
};
vector<vector<int>> Graph;
vector<int> depth; // depth[k] -> the depth of the k'th node.
vector<int> weight; // weight[k] -> the number of nodes in k'th node's subtree (including k).
vector<bool> used; // used[k] -> whether we visited k'th node.
vector<vector<int>> paths; // paths[k] -> k'th path of the heavy path decoposition
vector<int> whichPath; // whichPath[k] -> in which path is the k'th node
vector<int> pathPosition; // pathPosition[k] -> what's the index of the k'th node in its path
vector<int> pathsDaddy; // pathsDaddy[k] -> which node is k'th path's parent?
vector<SegmentTree> SegmentTrees; // SegmentTrees[k] -> segment tree for the k'th path
int N, M;
void ReadData()
{
scanf("%d%d", &N, &M);
Graph.resize(N, vector<int>());
value.resize(N);
depth.resize(N);
weight.resize(N);
used.resize(N);
whichPath.resize(N);
pathPosition.resize(N);
for (int i = 0; i < N; ++i)
scanf("%d", &value[i]);
for (int i = 0; i < N - 1; ++i) {
int x, y;
scanf("%d%d", &x, &y);
--x; --y;
Graph[x].emplace_back(y);
Graph[y].emplace_back(x);
}
}
void GetWeight(int k)
{
used[k] = 1;
for (auto it: Graph[k])
if (!used[it]) {
depth[it] = depth[k] + 1;
GetWeight(it);
weight[k] += weight[it];
}
weight[k] += 1;
}
void heavy(int k)
{
used[k] = true;
paths[(int)paths.size()-1].emplace_back(k);
whichPath[k] = (int)paths.size()-1;
pathPosition[k] = paths[whichPath[k]].size() - 1;
for (auto it: Graph[k]) {
if (!used[it]) {
if (paths.back().back() != k) {
paths.emplace_back(vector<int>());
pathsDaddy.emplace_back(k);
}
heavy(it);
}
}
}
void Decompose()
{
GetWeight(0);
fill(used.begin(), used.end(), false);
for (int i = 0; i < N; ++i)
for (int j = 1; j < Graph[i].size(); ++j)
if (weight[Graph[i][0]] < weight[Graph[i][j]])
swap(Graph[i][0], Graph[i][j]);
paths.emplace_back(vector<int>());
pathsDaddy.emplace_back(-1);
heavy(0);
}
void BuildSegmentTrees()
{
SegmentTrees.resize(paths.size());
for (int i = 0; i < paths.size(); ++i)
SegmentTrees[i].Build(paths[i]);
}
void Solve()
{
int x, y, op;
for (int i = 0; i < M; ++i) {
scanf("%d%d%d", &op, &x, &y);
--x;
if (op == 0) {
SegmentTrees[whichPath[x]].Update(pathPosition[x], y);
continue;
}
continue;
--y;
int answer = numeric_limits<int>::min();
while (whichPath[x] != whichPath[y]) {
if (depth[pathsDaddy[whichPath[x]]] < depth[pathsDaddy[whichPath[y]]])
swap(x,y);
// x is the deepest
if (whichPath[x] == 0) // this is the parent path
swap(x, y);
// x must be on a lower path
answer = max(answer, SegmentTrees[whichPath[x]].Query(0, pathPosition[x]));
x = pathsDaddy[whichPath[x]];
}
if (pathPosition[x] > pathPosition[y])
swap(x, y);
answer = max(answer, SegmentTrees[whichPath[x]].Query(pathPosition[x], pathPosition[y]));
printf("%d\n", answer);
}
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
ReadData();
Decompose();
BuildSegmentTrees();
Solve();
return 0;
}