#include <fstream>
#include <vector>
#define In "heavypath.in"
#define Out "heavypath.out"
#define Root 1
#define IT vector< int > ::iterator
#define Nmax 100004
#define NODE (node+decalaj)
#define LeftSon (2*node)
#define RightSon (2*node+1)
using namespace std;
ifstream f(In);
ofstream g(Out);
vector< int > Tree[Nmax];///arborele dat
vector<int > el[Nmax];///nodurile care fac parte din lantul i in ordine crescatoare dupa nivel
int niv[Nmax];///nivelul nodului i
int n, ans, L, v[Nmax];///valorea nodului i,L = numarul de lanturi
int LantDim[Nmax];///dimensiunea lantului i
int nr[Nmax];///numarul de elemente al subarborelui cu radacina in i
int Lant[Nmax];///indicele lantului din care face parte nodul i
int LantFather[Nmax];///indicele tatalui nodului cu cel mai mic nivel din lantul i
int LantSum[Nmax];///suma lungimilor lanturilor 1,2,...,i-1
int pos[Nmax];///pozitia nodului i in lantul din care face parte
class SegmentTree
{
public :
inline void Build(const int node,const int left,const int right,const int decalaj,int lant)
{
if(left == right )
{
aint[NODE] = v[el[lant][left]];
return ;
}
int middle = (left + right)>>1;
Build(LeftSon,left,middle,decalaj,lant);
Build(RightSon,middle+1,right,decalaj,lant);
aint[NODE] = max(aint[LeftSon+decalaj],aint[RightSon+decalaj]);
}
inline void Update(const int node,const int left,const int right,const int pos ,const int value,const int decalaj)
{
if(left == right )
{
aint[NODE] = value;
return ;
}
int middle = (left + right)>>1;
if(pos<=middle)
Update(LeftSon,left,middle,pos,value,decalaj);
else
Update(RightSon,middle+1,right,pos,value,decalaj);
aint[NODE] = max(aint[LeftSon+decalaj],aint[RightSon+decalaj]);
}
inline void Query(const int node,const int left,const int right,const int x ,const int y,const int decalaj)
{
if(x <= left && right <= y )
{
ans = max(ans,aint[NODE]);
return ;
}
int middle = (left + right)>>1;
if(x<=middle)
Query(LeftSon,left,middle,x,y,decalaj);
if(middle+1<=y)
Query(RightSon,middle+1,right,x,y,decalaj);
}
private :int aint[4*Nmax];
};
inline void Erase(const int node,const int Father)
{
IT it, del = Tree[node].end();
for(it = Tree[node].begin();it!=Tree[node].end(); ++it)
if(*it==Father)
del = it;
else
Erase(*it,node);
if(del!=Tree[node].end())
Tree[node].erase(del);
}
inline void DFS(const int node)
{
IT it;
bool frunza = 1;
int SonMAX = 0, lant;
nr[node] = 1;
for(it = Tree[node].begin(); it!= Tree[node].end(); ++it)
{
niv[*it] = niv[node]+1;
frunza = 0;
DFS(*it);
nr[node] += nr[*it];
if(nr[*it] > nr[SonMAX])
SonMAX= *it;
}
if(frunza)
{
++L;
Lant[node] = L;
LantDim[L] = 1;
el[L].push_back(node);
return ;
}
///punem nodul pe lantul fiului cu cele mai multe noduri in subarbore
lant = Lant[SonMAX];
Lant[node] = lant;
++LantDim[lant];
el[lant].push_back(node);
for(it = Tree[node].begin(); it!= Tree[node].end(); ++it)
if(*it!=SonMAX)
LantFather[Lant[*it]] = node;
}
inline void Reverse(const int i)
{
int j,n = LantDim[i],m;
m = (n>>1)+ (n&1);
if(n==1)
pos[el[i][1]] = 1;
for(j = 1;j <= m; ++j)
{
swap(el[i][j],el[i][n-j+1]);
pos[el[i][j]] = j;
pos[el[i][n-j+1]] = n-j+1;
}
}
SegmentTree A;
int main()
{
int i,x, y, m, t;
f>>n>>m;
for(i = 1;i <= n; ++i)
f>>v[i];
for(i = 1;i < n; ++i)
{
f>>x>>y;
el[i].push_back(0);
Tree[x].push_back(y);
Tree[y].push_back(x);
}
Erase(Root,0);
niv[Root] = 1;
DFS(Root);
IT it;
LantFather[1] = 1;
for(i = 1;i <= L; ++i)
{
Reverse(i);
if(i>1)
LantSum[i] = LantSum[i-1] + 4*LantDim[i-1];
A.Build(1,1,LantDim[i],LantSum[i],i);
}
for( ; m; --m)
{
f>>t>>x>>y;
if(!t)
A.Update(1,1,LantDim[Lant[x]],pos[x],y,LantSum[Lant[x]]);
else
{
ans = 0;
while(true)
{
if(Lant[x]==Lant[y])
{
if(niv[x]>niv[y])
swap(x,y);
A.Query(1,1,LantDim[Lant[x]],pos[x],pos[y],LantSum[Lant[x]]);
break;
}
if(niv[x] < niv[y])
swap(x,y);
A.Query(1,1,LantDim[Lant[x]],1,pos[x],LantSum[Lant[x]]);
x = LantFather[Lant[x]];
}
g<<ans<<"\n";
}
}
f.close();
g.close();
return 0;
}