#include <cstdio>
#include <vector>
using namespace std;
class ArbIntNod {
public:
int valoare;
int st, dr;
ArbIntNod *fs, *fd;
ArbIntNod(int st, int dr)
{
this->valoare = 0;
this->st = st;
this->dr = dr;
this->fs = NULL;
this->fd = NULL;
}
};
class ArbInt {
public:
ArbIntNod* radacina;
int dimensiune;
//int *date;
void makeArbInt(ArbIntNod* currNod)
{
if(currNod->st == currNod->dr)
return;
currNod->fs = new ArbIntNod(currNod->st,(currNod->st+currNod->dr)/2);
makeArbInt(currNod->fs);
currNod->fd = new ArbIntNod((currNod->st+currNod->dr)/2+1,currNod->dr);
makeArbInt(currNod->fd);
}
ArbInt(int dimensiune) {
this->radacina = new ArbIntNod(0,dimensiune-1);
makeArbInt(radacina);
/*this->dimensiune = dimensiune;
this->date = new int[this->dimensiune];
for(int i = 0; i < this->dimensiune; i++)
this->date[i] = 0;*/
}
void update(int index, int valoare, ArbIntNod* currNod) {
if(currNod->st == currNod->dr)
{
currNod->valoare = valoare;
return;
}
if(index <= currNod->fs->dr) update(index, valoare, currNod->fs);
else update(index, valoare, currNod->fd);
currNod->valoare = max(currNod->fs->valoare, currNod->fd->valoare);
//this->date[index] += valoare;
}
int queryMax(int inceput, int sfarsit, ArbIntNod *currNod) {
if(currNod->st >= inceput && currNod->dr <= sfarsit) return currNod->valoare;
int val1 = 0x80000000, val2 = 0x80000000;
if(inceput <= currNod->fs->dr) val1 = queryMax(inceput, sfarsit, currNod->fs);
if(currNod->fd->st <= sfarsit) val2 = queryMax(inceput, sfarsit, currNod->fd);
return max(val1, val2);
/*int answer = 0x80000000;
for (int i = inceput; i <= sfarsit; ++i) {
answer = max(answer, this->date[i]);
}
return answer;*/
}
void dump()
{
/*printf(" ( ");
for(int i = 0; i < dimensiune; i++)
printf("%3d ", date[i]);
printf(")");*/
}
};
class Nod;
class Lant {
public:
Nod* primulNod;
ArbInt* arbInt;
int lungime; // ?
Lant(Nod* primulNod)
{
this->primulNod = primulNod;
this->lungime = 1;
}
void dump()
{
this->arbInt->dump();
}
void setArbInt() {
this->arbInt = new ArbInt(this->lungime);
}
};
class Nod {
public:
//int index;
int adancime;
int greutate;
Nod* tata;
Nod* fiuGreu;
vector<Nod*> vecini;
Lant* lant;
int valoare;
Nod()
{
this->adancime = 0;
this->greutate = 0;
this->valoare = 0;
this->fiuGreu = NULL;
}
void dump(bool cuLant = true, int offset = 0) {
if (cuLant) {
for (int i = 0; i < offset; ++i) {
printf(" ");
printf(" ");
}
Nod* nod = this;
while (nod != NULL) {
printf(" - %.8p (%.8p)", nod, nod->lant);
fflush(stdout);
nod = nod->fiuGreu;
}
this->lant->dump();
printf("\n");
}
if(this->fiuGreu != NULL)
this->fiuGreu->dump(false, offset + 1);
for (int i = 0; i < (int)this->vecini.size(); ++i) {
Nod* fiu = this->vecini[i];
if (fiu != this->tata && fiu != this->fiuGreu) {
fiu->dump(true, offset + 1);
}
}
}
void update(int valoare)
{
this->lant->arbInt->update(this->adancime-this->lant->primulNod->adancime, valoare, this->lant->arbInt->radacina);
}
};
class Arbore {
Nod* radacina;
void dfs(Nod* nod)
{
nod->greutate = 1;
for(int i = 0; i < (int)nod->vecini.size(); i++) {
Nod* fiu = nod->vecini[i];
if(fiu != nod->tata) {
fiu->tata = nod;
fiu->adancime = nod->adancime+1;
dfs(fiu);
nod->greutate += fiu->greutate;
if(nod->fiuGreu == NULL || fiu->greutate > nod->fiuGreu->greutate)
nod->fiuGreu = fiu;
}
}
if(nod->fiuGreu == NULL)
nod->lant = new Lant(nod);
else {
nod->lant = nod->fiuGreu->lant;
nod->lant->primulNod = nod;
nod->lant->lungime++;
}
for(int i = 0; i < (int)nod->vecini.size(); i++) {
Nod* fiu = nod->vecini[i];
if(fiu != nod->tata && fiu != nod->fiuGreu)
fiu->lant->setArbInt();
}
}
public:
//Nod noduri[];
Nod* noduri;
Arbore(int N, int* muchii[2]) {
this->noduri = new Nod[1 + N];
this->radacina = &this->noduri[1];
for(int i = 0; i < N-1; i++)
{
noduri[muchii[0][i]].vecini.push_back(&noduri[muchii[1][i]]);
noduri[muchii[1][i]].vecini.push_back(&noduri[muchii[0][i]]);
}
this->radacina->adancime = 0;
dfs(radacina);
//for(;;);
radacina->lant->setArbInt();
}
void dump() {
this->radacina->dump();
printf("\n");
}
int queryMax(int index1, int index2) {
Nod* nod1 = &noduri[index1];
Nod* nod2 = &noduri[index2];
int maxim = 0;
while(nod1->lant != nod2->lant) {
if(nod1->lant->primulNod->adancime > nod2->lant->primulNod->adancime) {
maxim = max(maxim, nod1->lant->arbInt->queryMax(0, nod1->adancime - nod1->lant->primulNod->adancime, nod1->lant->arbInt->radacina));
nod1 = nod1->lant->primulNod->tata;
} else {
maxim = max(maxim, nod2->lant->arbInt->queryMax(0, nod2->adancime - nod2->lant->primulNod->adancime, nod2->lant->arbInt->radacina));
nod2 = nod2->lant->primulNod->tata;
}
}
int lung = nod1->lant->primulNod->adancime;
if(nod1->adancime > nod2->adancime)
maxim = max(maxim, nod1->lant->arbInt->queryMax(nod2->adancime-lung, nod1->adancime-lung, nod1->lant->arbInt->radacina));
else
maxim = max(maxim, nod1->lant->arbInt->queryMax(nod1->adancime-lung, nod2->adancime-lung, nod1->lant->arbInt->radacina));
return maxim;
}
void update(int index, int valoare) {
noduri[index].update(valoare);
}
};
int main(void) {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int n, m;
int* muchii[2];
scanf("%d%d", &n,&m);
muchii[0] = new int[n-1];
muchii[1] = new int[n-1];
for(int i = 0; i < n; i++)
scanf("%d%d", &muchii[0][i], &muchii[1][i]);
Arbore* arbore = new Arbore(n, muchii);
int type,x,y;
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &type, &x, &y);
if(type == 0)
arbore->update(x,y);
else
printf("%d\n", arbore->queryMax(x,y));
}
/*int i;
int arg1, arg2;
int N, Q;
int* muchii[2];
char ch;
scanf("%d", &N);
muchii[0] = new int[N - 1];
muchii[1] = new int[N - 1];
for (i = 0; i < N - 1; ++i) {
scanf("%d %d", &muchii[0][i], &muchii[1][i]);
}
Arbore* arbore = new Arbore(N, muchii);
//arbore->dump();
scanf("%d", &Q);
for (int i = 0; i < Q; ++i) {
scanf("\n%c %d %d", &ch, &arg1, &arg2);
if (ch == 'I') {
arbore->update(arg1, arg2);
} else if (ch == 'G') {
printf("%d\n", arbore->queryMax(arg1, arg2));
}
// arbore->dump();
}*/
return 0;
}