#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <fstream>
using namespace std;
const string file = "heavypath";
const string infile = file + ".in";
const string outfile = file + ".out";
int N, M;
vector<vector<int> > G;
vector<int> values;
vector<int> level;
vector<int> weight;
vector<vector<int> > Paths;
vector<int> pathParent;
vector<int> pathId;
vector<int> pathPos;
class SegmentTree
{
public:
SegmentTree(int low, int hi);
void Update(int low, int hi, int value);
int Query(int low, int hi);
protected:
private:
void Update(int nod, int st, int dr, int low, int hi, int value);
int Query(int nod, int st, int dr, int low, int hi);
int _low;
int _hi;
vector<int> _data;
};
SegmentTree::SegmentTree(int low, int hi)
{
this->_low = low;
this->_hi = hi;
int size = hi - low + 1;
int c = 1;
while( c < size) c <<= 1;
c <<= 1;
this->_data.resize(c + 1);
}
void SegmentTree::Update(int low, int hi, int value)
{
Update(1, _low, _hi, low, hi, value);
}
int SegmentTree::Query(int low, int hi)
{
return Query(1, _low, _hi, low, hi);
}
void SegmentTree::Update(int nod, int st, int dr, int low, int hi, int value)
{
if( low <= st && dr <= hi)
{
_data[nod] = value;
}
else
{
int mid = (st + dr) / 2;
if(low <= mid)
Update(nod * 2, st, mid, low, hi, value);
if(mid < hi)
Update(nod* 2 + 1, mid + 1, dr, low, hi, value);
_data[nod] = max(_data[nod*2], _data[nod*2+1]);
}
}
int SegmentTree::Query(int nod, int st, int dr, int low, int hi)
{
if(low <= st && dr <= hi)
{
return _data[nod];
}
else
{
int result = 0;
int mid = (st + dr)/2;
if(low <= mid)
result = max(result, Query(nod*2, st, mid, low, hi));
if(mid < hi)
result = max(result, Query(nod*2 + 1, mid + 1, dr, low, hi));
return result;
}
}
void dfs(int nod)
{
stack<int> s;
vector<bool> seen(N + 1);
vector<bool> added(N + 1);
s.push(nod);
added[nod] = true;
level[nod] = 0;
while(s.empty() == false)
{
int current = s.top();
if(seen[current] == false)
{
seen[current] = true;
for(vector<int>::iterator itr = G[current].begin();
itr != G[current].end();
itr++)
{
if(added[*itr] == false)
{
added[*itr] = true;
level[*itr] = level[current] + 1;
s.push(*itr);
}
}
}
else
{
s.pop();
int maxWeight = 0;
for(vector<int>::iterator itr = G[current].begin();
itr != G[current].end();
itr++)
{
if(level[current] < level[*itr])
{
weight[current] += weight[*itr];
if(weight[maxWeight] < weight[*itr])
maxWeight = *itr;
}
}
if(maxWeight == 0)
{
pathId[current] = Paths.size();
pathPos[current] = 0;
vector<int> newPath;
newPath.push_back(current);
pathParent.push_back(0);
Paths.push_back(newPath);
}
else
{
pathId[current] = pathId[maxWeight];
pathPos[current] = Paths[pathId[maxWeight]].size();
Paths[pathId[maxWeight]].push_back(current);
for(vector<int> :: iterator itr = G[current].begin();
itr != G[current].end();
itr++)
{
if(level[current] < level[*itr] && *itr != maxWeight)
{
pathParent[pathId[*itr]] = current;
}
}
}
}
}
}
int main()
{
fstream fin(infile.c_str(), ios::in);
fin >> N >> M;
G.resize(N + 1);
values.resize(N + 1);
for(int i = 0; i < N; i++)
{
fin >> values[i + 1];
}
for(int i = 1; i < N; i++)
{
int x, y;
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
pathId.resize(N + 1, -1);
pathPos.resize(N + 1, -1);
weight.resize(N + 1, 1);
weight[0] = 0;
level.resize(N + 1);
dfs(1);
vector<SegmentTree> trees;
for(unsigned i = 0; i < Paths.size(); i++)
{
trees.push_back(SegmentTree(0, Paths[i].size() - 1));
for(unsigned j = 0; j < Paths[i].size(); j++)
{
trees[i].Update(j, j, values[Paths[i][j]]);
}
}
fstream fout(outfile.c_str(), ios::out);
for(int i = 0; i < M; i++)
{
int op, x, y;
fin >> op >> x >> y;
if(op == 0)
{
trees[pathId[x]].Update(pathPos[x], pathPos[x], y);
}
else if(op == 1)
{
int sol = 0;
while(true)
{
if(pathId[x] == pathId[y])
{
sol = max(sol, trees[pathId[x]].Query(min(pathPos[x], pathPos[y]), max(pathPos[x], pathPos[y])));
break;
}
if(level[pathParent[pathId[x]]] < level[pathParent[pathId[y]]])
swap(x, y);
sol = max(sol, trees[pathId[x]].Query(pathPos[x], Paths[pathId[x]].size() - 1));
x = pathParent[pathId[x]];
}
fout << sol << "\n";
}
}
fin.close();
fout.close();
}