#include <bits/stdc++.h>
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
const int nmax = 100004;
int v[nmax];
pair <int, int> where[nmax];
class arbint
{
public:
int tree[nmax * 4];
int n, last;
arbint(vector <int> &vec)
{
this -> n = vec.size();
this -> last = vec[n - 1];
memset(this -> tree, 0, sizeof(this -> tree));
for (int i = 0; i < n; ++ i)
update(i + 1, v[vec[i]]);
}
int findMaxFromNode(int nod)
{
return findMax(where[nod].second, this -> n);
}
int findMax(const int a, const int b)
{
return private_findMax(1, 1, n, a, b);
}
void update(const int id, const int x)
{
private_update(1, 1, n, id, x);
}
private:
int private_findMax(int nod, int i, int j, const int a, const int b)
{
if (a <= i && j <= b)
return tree[nod];
int m = (i + j) / 2;
int ans = 0;
if (a <= m)
ans = max(ans, private_findMax(nod * 2, i, m, a, b));
if (b > m)
ans = max(ans, private_findMax(nod * 2 + 1, m + 1, j, a, b));
return ans;
}
void private_update(int nod, int i, int j, const int id, const int x)
{
if (i == j)
{
tree[nod] = x;
return;
}
int m = (i + j) / 2;
if (id <= m)
private_update(nod * 2, i, m, id, x);
else
private_update(nod * 2 + 1, m + 1, j, id, x);
tree[nod] = max(tree[nod * 2], tree[nod * 2 + 1]);
}
};
bool fv[nmax];
int father[nmax];
int weight[nmax];
vector <int> vec[nmax];
vector <vector <int>> nodes;
vector <arbint> allTrees;
void dfs(int nod)
{
fv[nod] = 1;
int maxSon = 0;
for (auto el: vec[nod])
if (!fv[el])
{
father[el] = nod;
dfs(el);
weight[nod] += weight[el] + 1;
if (maxSon == 0 || weight[maxSon] < weight[el])
maxSon = el;
}
if (weight[nod] == 0)
{
nodes.push_back({nod});
where[nod].first = nodes.size() - 1;
where[nod].second = 1;
return;
}
nodes[where[maxSon].first].push_back(nod);
where[nod].first = where[maxSon].first;
where[nod].second = where[maxSon].second + 1;
}
int merge(int nodX, int nodY)
{
int ans = 0;
while (where[nodX].first != where[nodY].first)
{
int first = allTrees[where[nodX].first].findMaxFromNode(nodX);
int second = allTrees[where[nodY].first].findMaxFromNode(nodY);
ans = max(ans, max(first, second));
if (weight[nodX] > weight[nodY])
swap(nodX, nodY);
nodX = father[allTrees[where[nodX].first].last];
}
if (where[nodX].second > where[nodY].second)
swap(nodX, nodY);
int final = allTrees[where[nodX].first].findMax(where[nodX].second, where[nodY].second);
return max(ans, final);
}
int main()
{
int n, m;
f >> n >> m;
for (int i = 1; i <= n; ++ i)
f >> v[i];
for (int i = 1; i < n; ++ i)
{
int x, y;
f >> x >> y;
vec[x].push_back(y);
vec[y].push_back(x);
}
father[1] = 1;
dfs(1);
for (auto el: nodes)
{
auto newTree(el);
allTrees.push_back(newTree);
}
for (int i = 1; i <= m; ++ i)
{
int op, x, y;
f >> op >> x >> y;
if (op == 1)
g << merge(x, y) << '\n';
else
allTrees[where[x].first].update(where[x].second, y);
}
}