#include <bits/stdc++.h>
using namespace std;
const int NMAX = 1e5;
int n;
vector<int> graph[NMAX];
int aint[2 * NMAX];
int heavy[NMAX];
int head[NMAX];
int parent[NMAX];
int depth[NMAX];
int euler[NMAX];
int v[NMAX];
int aint_join(int a, int b) {
return (a > b ? a : b);
}
void aint_update(int node, int left, int right, int poz, int val) {
if(left == right) {
aint[node] = val;
} else {
int leftChild, rightChild, mid;
mid = (left + right) / 2;
leftChild = node + 1;
rightChild = node + 2 * (mid - left + 1);
if(poz <= mid)
aint_update(leftChild, left, mid, poz, val);
else
aint_update(rightChild, mid + 1, right, poz, val);
aint[node] = aint_join(aint[leftChild], aint[rightChild]);
}
}
int aint_query(int node, int left, int right, int qLeft, int qRight) {
int leftChild, rightChild, mid;
mid = (left + right) / 2;
leftChild = node + 1;
rightChild = node + 2 * (mid - left + 1);
if(left == qLeft && right == qRight)
return aint[node];
else {
if(qRight <= mid)
return aint_query(leftChild, left, mid, qLeft, qRight);
if(qLeft > mid)
return aint_query(rightChild, mid + 1, right, qLeft, qRight);
return aint_join(aint_query(leftChild, left, mid, qLeft, mid),
aint_query(rightChild, mid + 1, right, mid + 1, qRight));
}
}
int dfs(int node, int nodeParent = -1) {
int maxSize = 0, size = 1;
parent[node] = nodeParent;
heavy[node] = -1;
for(auto neighbour : graph[node]) {
if(neighbour != nodeParent) {
depth[neighbour] = depth[node] + 1;
int neighbourSize = dfs(neighbour, node);
size += neighbourSize;
if(neighbourSize > maxSize) {
maxSize = neighbourSize;
heavy[node] = neighbour;
}
}
}
return size;
}
int eulerTime;
void decompose(int node, int nodeParent, int nodeHead) {
head[node] = nodeHead;
euler[node] = eulerTime++;
if(heavy[node] != -1) // not leaf
decompose(heavy[node], node, nodeHead);
for(auto neighbour : graph[node]) {
if(neighbour != nodeParent && neighbour != heavy[node])
decompose(neighbour, node, neighbour);
}
}
void heavy_update(int node, int val) {
aint_update(0, 0, n - 1, euler[node], val);
}
int heavy_query(int a, int b) {
int ans = 0;
while(head[a] != head[b]) {
if(depth[head[a]] < depth[head[b]])
swap(a, b);
ans = max(ans, aint_query(0, 0, n - 1, euler[head[a]], euler[a]));
a = parent[head[a]];
}
ans = max(ans, aint_query(0, 0, n - 1, min(euler[a], euler[b]), max(euler[a], euler[b])));
return ans;
}
int main() {
int q;
FILE *fin, *fout;
fin = fopen("heavypath.in", "r");
fout = fopen("heavypath.out", "w");
fscanf(fin, "%d%d", &n, &q);
for(int i = 0; i < n; i++)
fscanf(fin, "%d", &v[i]);
for(int i = 0; i < n - 1; i++) {
int a, b;
fscanf(fin, "%d%d", &a, &b);
a--;
b--;
graph[a].push_back(b);
graph[b].push_back(a);
}
dfs(0);
eulerTime = 0;
decompose(0, -1, 0);
/*for(int i = 0; i < n; i++) {
cout << "Node: " << i + 1 << " heavy: " << heavy[i] + 1<< '\n';
}
cout << endl;
for(int i = 0; i < n; i++) {
cout << "Node: " << i + 1 << " head: " << head[i] + 1 << '\n';
}
cout << endl;*/
for(int i = 0; i < n; i++)
heavy_update(i, v[i]);
for(int i = 0; i < q; i++) {
int a, b, c;
fscanf(fin, "%d%d%d", &a, &b, &c);
if(a == 0) {
heavy_update(b - 1, c);
} else {
fprintf(fout, "%d\n", heavy_query(b - 1, c - 1));
}
}
fclose(fin);
fclose(fout);
return 0;
}