#include <fstream>
#include <iostream>
#include <cstdlib>
#include <iterator>
#include <vector>
#include <algorithm>
#include <limits>
#define MAX_SIZE 100001
using namespace std;
typedef unsigned int uint32;
template<class T, class Compare = less<T> >
class CIntervalTree
{
public:
CIntervalTree(const int size, const T& defaultValue) :
intervalSize(size)
{
vValues.resize(size + 1);
vValues[size] = defaultValue;
intervalTree = (int*)calloc((4*size+2), sizeof(int));
}
~CIntervalTree()
{
vValues.clear();
free(intervalTree);
}
inline void Update(const int index, const T& value)
{
vValues[index] = value;
UpdateIndex(index);
}
inline void Update(const int index)
{
UpdateIndex(index);
}
inline void UpdateIndex(const int index)
{
int left = 0, right = intervalSize-1;
int intervalTreeIndex = 0;
while (left < right)
{
const int mid = left + (right-left)/2;
if (index <= mid)
{
intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
right = mid;
}
else
{
intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
left = mid+1;
}
}
if (left == index)
{
intervalTree[intervalTreeIndex] = index;
int parent = GetZeroBasedIndexOfParent(intervalTreeIndex);
while(parent >= 0)
{
if (compare(vValues[intervalTree[GetLeftSubtree(parent)]], vValues[intervalTree[GetRightSubtree(parent)]]))
{
intervalTree[parent] = intervalTree[GetLeftSubtree(parent)];
}
else
{
intervalTree[parent] = intervalTree[GetRightSubtree(parent)];
}
intervalTreeIndex = parent;
parent = GetZeroBasedIndexOfParent(intervalTreeIndex);
}
}
}
inline int QueryIndex(const int l, const int r) const
{
int intervalTreeIndex = 0;
int left = 0, right = intervalSize-1;
if (l == r)
{
return QueryElementaryInterval(l);
}
int mid = left + (right-left)/2;
while (r <= mid || l > mid)
{
if (r <= mid)
{
right = mid;
intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
}
else if (l > mid)
{
left = mid+1;
intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
}
mid = left + (right-left)/2;
}
const int leftIndex = QueryLeftSubInterval(left, mid, l, GetLeftSubtree(intervalTreeIndex));
const int rightIndex = QueryRightSubInterval(mid+1, right, r, GetRightSubtree(intervalTreeIndex));
if (compare(vValues[leftIndex], vValues[rightIndex]))
{
return leftIndex;
}
return rightIndex;
}
inline T& QueryValue(const int l, const int r)
{
return vValues[QueryIndex(l,r)];
}
inline const T& QueryValue(const int l, const int r) const
{
return vValues[QueryIndex(l,r)];
}
inline T& GetValueAt(const int index)
{
return vValues[index];
}
inline const T& GetValueAt(const int index) const
{
return vValues[index];
}
private:
inline int GetZeroBasedIndexOfParent(int index) const
{
return (index-1-!(index%2)) / 2;
}
inline int GetLeftSubtree(int index) const
{
return (index<<1)+1;
}
inline int GetRightSubtree(int index) const
{
return (index+1)<<1;
}
inline int QueryElementaryInterval(const int index) const
{
int left = 0, right = intervalSize-1;
int intervalTreeIndex = 0;
while (left < right)
{
const int mid = left + (right-left)/2;
if (index <= mid)
{
intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
right = mid;
}
else
{
intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
left = mid+1;
}
}
if (left == index)
{
return intervalTree[intervalTreeIndex];
}
return intervalTree[intervalSize];
}
inline int QueryLeftSubInterval(int left, int right, const int finalLeft, int intervalTreeIndex) const
{
int foundIndex = intervalSize;
while (finalLeft != left)
{
const int mid = left + (right-left)/2;
if (finalLeft <= mid)
{
if (compare(vValues[intervalTree[GetRightSubtree(intervalTreeIndex)]], vValues[foundIndex]))
{
foundIndex = intervalTree[GetRightSubtree(intervalTreeIndex)];
}
intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
right = mid;
}
else
{
left = mid+1;
intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
}
}
if (compare(vValues[intervalTree[intervalTreeIndex]], vValues[foundIndex]))
{
foundIndex = intervalTree[intervalTreeIndex];
}
return foundIndex;
}
inline int QueryRightSubInterval(int left, int right, const int finalRight, int intervalTreeIndex) const
{
int foundIndex = intervalSize;
while (finalRight != right)
{
const int mid = left + (right-left)/2;
if (finalRight > mid)
{
if (compare(vValues[intervalTree[GetLeftSubtree(intervalTreeIndex)]], vValues[foundIndex]))
{
foundIndex = intervalTree[GetLeftSubtree(intervalTreeIndex)];
}
intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
left = mid+1;
}
else
{
right = mid;
intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
}
}
if (compare(vValues[intervalTree[intervalTreeIndex]], vValues[foundIndex]))
{
foundIndex = intervalTree[intervalTreeIndex];
}
return foundIndex;
}
Compare compare;
const int intervalSize;
int *intervalTree;
vector<T> vValues;
};
typedef vector<vector<int> > Graph;
struct VertexIndex
{
int WhatPath;
int WhatPosition;
};
struct Path
{
Path() :
Parent(-1),
Level(std::numeric_limits<int>::max()),
IntervalTree(NULL)
{}
~Path()
{
if (IntervalTree != NULL)
{
delete IntervalTree;
}
}
size_t size() const
{
return vVertexes.size();
}
int Parent;
int Level;
vector<int> vVertexes;
CIntervalTree<int, greater<int> >* IntervalTree;
};
vector<VertexIndex> vVertexIndex;
vector<Path> vPaths;
Graph graph;
void DFS(int node, int depth)
{
static bool vUsed[MAX_SIZE] = {true, false};
static int vWeight[MAX_SIZE];
int pathChosen = node;
int maxWeight = -1;
vUsed[node] = true;
vWeight[node] = 1;
for (vector<int>::const_iterator it=graph[node].begin();
it != graph[node].end();
++it)
{
if (vUsed[*it] == false)
{
DFS(*it, depth+1);
vWeight[node] += vWeight[*it];
if (maxWeight < vWeight[*it])
{
maxWeight = vWeight[*it];
pathChosen = vVertexIndex[*it].WhatPath;
}
}
}
vVertexIndex[node].WhatPath = pathChosen;
vVertexIndex[node].WhatPosition = vPaths[pathChosen].size();
vPaths[pathChosen].vVertexes.push_back(node);
vPaths[pathChosen].Level = std::min(depth, vPaths[pathChosen].Level);
for (vector<int>::const_iterator it=graph[node].begin();
it != graph[node].end();
++it)
{
if (vVertexIndex[*it].WhatPath != pathChosen)
{
vPaths[vVertexIndex[*it].WhatPath].Parent = node;
}
}
}
int main()
{
int n, m;
vector<int> vVertexValues;
fstream fin("heavypath.in", fstream::in);
fstream fout("heavypath.out", fstream::out);
fin >> n >> m;
//cout << n << " " << m << endl;
graph.resize(n);
vVertexValues.resize(n);
vVertexIndex.resize(n);
vPaths.resize(n);
for (int i=0; i<n; ++i)
{
fin >> vVertexValues[i];
//cout << vVertexValues[i] << " ";
}
//cout << endl;
for (int i=0; i<n-1; ++i)
{
int x, y;
fin >> x >> y;
graph[x-1].push_back(y-1);
graph[y-1].push_back(x-1);
}
/*for (int i=0; i<n; ++i)
{
cout << i + 1 << " --> ";
for (vector<int>::const_iterator it=graph[i].begin();
it != graph[i].end();
++it)
{
cout << *it + 1 << " ";
}
cout << endl;
}*/
DFS(0, 0);
for (int i=0; i<vPaths.size(); ++i)
{
reverse(vPaths[i].vVertexes.begin(), vPaths[i].vVertexes.end());
vPaths[i].IntervalTree = new CIntervalTree<int, greater<int> >(vPaths[i].vVertexes.size(), 0);
for (int j=0; j<vPaths[i].vVertexes.size(); ++j)
{
vPaths[i].IntervalTree->Update(j, vVertexValues[vPaths[i].vVertexes[j]]);
vVertexIndex[vPaths[i].vVertexes[j]].WhatPosition = j;
}
}
vVertexValues.clear();
/*for (int i=0; i<n; ++i)
{
cout << vVertexIndex[i].WhatPath << " " << vVertexIndex[i].WhatPosition << endl;
}
cout << endl;*/
/*for (int i=0; i<vPaths.size(); ++i)
{
if (vPaths[i].Level < n)
{
cout << vPaths[i].Parent << " " << vPaths[i].Level << endl;
for (int j=0; j<vPaths[i].vVertexes.size(); ++j)
{
cout << vPaths[i].vVertexes[j] << " ";
}
cout << endl << endl;
}
}*/
for (int i=0; i<m; ++i)
{
int t, x, y;
fin >> t >> x >> y;
switch (t)
{
case 0:
{
vPaths[vVertexIndex[x-1].WhatPath].IntervalTree->Update(vVertexIndex[x-1].WhatPosition, y);
}; break;
case 1:
{
x--;
y--;
if (vPaths[vVertexIndex[x].WhatPath].Level < vPaths[vVertexIndex[y].WhatPath].Level)
{
swap(x, y);
}
int ret = -1;
int WhatPath = vVertexIndex[x].WhatPath;
while (WhatPath != vVertexIndex[y].WhatPath)
{
if (vPaths[vVertexIndex[x].WhatPath].Level < vPaths[vVertexIndex[y].WhatPath].Level)
{
swap(x, y);
WhatPath = vVertexIndex[x].WhatPath;
}
ret = std::max(ret, vPaths[WhatPath].IntervalTree->QueryValue(0, vVertexIndex[x].WhatPosition));
x = vPaths[WhatPath].Parent;
WhatPath = vVertexIndex[x].WhatPath;
}
if (vVertexIndex[x].WhatPosition > vVertexIndex[y].WhatPosition)
{
swap(x, y);
}
ret = std::max(ret, vPaths[WhatPath].IntervalTree->QueryValue(vVertexIndex[x].WhatPosition, vVertexIndex[y].WhatPosition));
fout << ret << "\n";
}; break;
}
}
fin.close();
fout.close();
return 0;
}