#include<bits/stdc++.h>
using namespace std;
/*

██╗    ██╗██████╗ ██╗████████╗████████╗███████╗███╗   ██╗    ██████╗ ██╗   ██╗
██║    ██║██╔══██╗██║╚══██╔══╝╚══██╔══╝██╔════╝████╗  ██║    ██╔══██╗╚██╗ ██╔╝
██║ █╗ ██║██████╔╝██║   ██║      ██║   █████╗  ██╔██╗ ██║    ██████╔╝ ╚████╔╝
██║███╗██║██╔══██╗██║   ██║      ██║   ██╔══╝  ██║╚██╗██║    ██╔══██╗  ╚██╔╝
╚███╔███╔╝██║  ██║██║   ██║      ██║   ███████╗██║ ╚████║    ██████╔╝   ██║
 ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝   ╚═╝      ╚═╝   ╚══════╝╚═╝  ╚═══╝    ╚═════╝    ╚═╝

     ███╗   ███╗   ██╗██████╗ ██████╗  █████╗ ██╗  ██╗██╗███╗   ███╗
     ████╗ ████║   ██║██╔══██╗██╔══██╗██╔══██╗██║  ██║██║████╗ ████║
     ██╔████╔██║   ██║██████╔╝██████╔╝███████║███████║██║██╔████╔██║
     ██║╚██╔╝██║   ██║██╔══██╗██╔══██╗██╔══██║██╔══██║██║██║╚██╔╝██║
     ██║ ╚═╝ ██║██╗██║██████╔╝██║  ██║██║  ██║██║  ██║██║██║ ╚═╝ ██║
     ╚═╝     ╚═╝╚═╝╚═╝╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚═╝     ╚═╝
*/
#define speed  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define FOR(n) for(int i=0;i<n;i++)
#define For(i, begin, end) for (__typeof(end) i = (begin) - ((begin) > (end)); i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin) > (end)))
#define E "\n"
#define all(e) e.begin(),e.end()
#define F first
#define S second
#define pi (acos(-1))
#define rad(x) ((x*pi)/(ld)(180))
#define perc(x) fixed<<setprecision(x)
/*****
#define cross(a, b) ((conj(a) * (b)).Y)
#define dot(a, b) ((conj(a) * (b)).X)
#define vec(a,b) ((b) - (a))
#define rot(p,angle) (p)*polar((double)(1),angle)
#define rot2(p,angle,a) ((p)-(a)) *(polar((ld)(1),angle)+ (a))
#define x real()
#define y imag()
*****/
typedef long long int ll; typedef unsigned long long ull; typedef long double ld;typedef complex<ld> point; typedef tuple<double,double,double> line;
ll gcd(ll x,ll y){if(!y)return x; return gcd(y,x%y);};   ll lcm(ll x,ll y){return (x*y)/__gcd(x,y);}
const int N=1e4+5;
string s;
map<char,char>mp;
bool check()
{
    mp['o']='o',mp['O']='O',mp['p']='q',mp['q']='p',mp['d']='b',mp['H']='H',
    mp['A']='A',mp['I']='I',mp['i']='i',mp['l']='l',mp['M']='M',mp['T']='T',
    mp['V']='V',mp['v']='v',mp['w']='w',mp['W']='W',mp['x']='x',mp['X']='X',
    mp['Y']='Y',mp['b']='d';
    int a=0, b=s.size()-1;

    while(a<b)
    {
        if(mp[s[a]]!=s[b])return 0;
        a++,b--;
    }

    return 1;
}

int main(){ speed;
cin>>s;

check()?cout<<"TAK":cout<<"NIE";

return 0;}


#include<bits/stdc++.h>
using namespace std;

#define speed  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define FOR(n) for(int i=0;i<n;i++)
#define For(i, begin, end) for (__typeof(end) i = (begin) - ((begin) > (end)); i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin) > (end)))
#define E "\n"
#define all(e) e.begin(),e.end()
#define F first
#define S second
#define pi (acos(-1))
#define rad(x) ((x*pi)/(ld)(180))
#define perc(x) fixed<<setprecision(x)
/*****
#define cross(a, b) ((conj(a) * (b)).Y)
#define dot(a, b) ((conj(a) * (b)).X)
#define vec(a,b) ((b) - (a))
#define rot(p,angle) (p)*polar((double)(1),angle)
#define rot2(p,angle,a) ((p)-(a)) *(polar((ld)(1),angle)+ (a))
#define x real()
#define y imag()
*****/
typedef long long int ll; typedef unsigned long long ull; typedef long double ld;typedef complex<ld> point; typedef tuple<double,double,double> line;
ll gcd(ll x,ll y){if(!y)return x; return gcd(y,x%y);};   ll lcm(ll x,ll y){return (x*y)/__gcd(x,y);}
const int N=1e4+5;
string s;
map<char,char>mp;
bool check()
{
    mp['o']='o',mp['O']='O',mp['p']='q',mp['q']='p',mp['d']='b',mp['H']='H',
    mp['A']='A',mp['I']='I',mp['M']='M',mp['T']='T',
    mp['V']='V',mp['v']='v',mp['w']='w',mp['W']='W',mp['x']='x',mp['X']='X',
    mp['Y']='Y',mp['b']='d';
    int a=0, b=s.size()-1;

    while(a<=b)
    {
        if(mp[s[a]]!=s[b])return 0;
        a++,b--;
    }

    return 1;
}

int main(){ speed;
cin>>s;

check()?cout<<"TAK":cout<<"NIE";

return 0;}


#include <bits/stdc++.h>

using namespace std;
#define ll long long

ll prime(ll n)
{
    if (n<2) return 0;
    if (n%2==0 && n>2) return 0;
    for (int i=2; i*i<=n; i++)
        if (n%i==0) return 0;
    return 1;
}

int main()
{
    string s,s2;
    cin >> s;
    s2=s;
    reverse(s2.begin() , s2.end());
    if (s==s2 && s.size()%2) cout << "TAK\n";
    else cout << "NIE\n";

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';
m['p'] = 'q';
string s;
int n;
cin>>s;
n =s.size();

if(n==1)
{
     if(s[0]==m[s[n-1]])
        cout<<"TAK";
     else
     cout<<"NIE";
}
else{
    int f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    if(n&1)
     if(s[n/2]!=m[s[n/2]])
       f=1;
    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';

string s;
int n;
cin>>s;
n =s.size();

if(n==1)
{
     if(s[0]==m[s[n-1]])
        cout<<"TAK";
     else
     cout<<"NIE";
}
else{
    int f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    if(n&1)
     if(s[n/2]!=m[s[n/2]])
       f=1;
    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';
m['p']  = 'q';
m['q']  = 'p';

string s;
int n;
cin>>s;
n =s.size();

if(n==1)
{
     if(s[0]==m[s[n-1]])
        cout<<"TAK";
     else
     cout<<"NIE";
}
else{
    int f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    if(n&1)
     if(s[n/2]!=m[s[n/2]])
       f=1;
    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';

string s;
int n;
cin>>s;
n =s.size();

if(n==1)
{
     if(s[0]==m[s[n-1]])
        cout<<"TAK";
     else
     cout<<"NIE";
}
else{
    int f=1;
    if(n&1){
            f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    }

    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';

string s;
int n;
cin>>s;
n =s.size();

if(n==1)
    cout<<"TAK";
else{
    int f=1;
    if(n&1){
            f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    }

    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';

string s;
int n;
cin>>s;
n =s.size();

if(n==1)
{
     if(s[0]==m[s[n-1]])
        cout<<"TAK";
     else
     cout<<"NIE";
}
else{
    int f=1;
    if(n&1){
            f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    }

     if(s[n/2]!=m[s[n/2]])
       f=1;
    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define sd(x) scanf("%d",&x)
#define pf(x) printf("%d",x)
#define ALL(x) (x.begin(),x.end())
#define pb push_back
#define BIG 1000000007LL

int main() {

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

//freopen("input.txt","r",stdin);

int test=1;
//cin>>test;

while(test--){

map<char,char> m;

m['A'] = 'A';
m['b'] = 'd';
m['d'] = 'b';
m['H'] = 'H';
m['I'] = 'I';
m['M'] = 'M';
m['O'] = 'O';
m['o'] = 'o';
m['T'] = 'T';
m['U'] = 'U';
m['V'] = 'V';
m['v'] = 'v';
m['W'] = 'W';
m['w'] = 'w';
m['X'] = 'X';
m['x'] = 'x';
m['Y'] = 'Y';

string s;
int n;
cin>>s;
n =s.size();

if(n==1)
    cout<<"NIE";
else{
    int f=1;
    if(n&1){
            f=0;
    for(int i=0;i<n/2;i++)
    {
        if(s[i]!=m[s[n-1-i]])
            f=1;
    }

    }

    if(f==0)
        cout<<"TAK";
    else
        cout<<"NIE";
}

}
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd' || x == 'q' && y == 'p';
}
int main() {
	IO
	string same = "AHIMOoTuUVvWwXxY";
	string s;
	cin >> s;
	if (s.size() == 1){
		if (same.find(s[0]) != -1)
			cout << "TAK";
		else
		cout << "NIE";
	return 0;
	}
	for (int i = 0, j = s.size() - 1; i <= j; i++, j--){
		if (same.find(s[i]) != -1 && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd' || x == 'q' && y == 'p';
}
int main() {
	IO
	string same = "AHIMmOoTuUVvWwXxY";
	string s;
	cin >> s;
	if (s.size() == 1){
		if (same.find(s[0]) != -1)
			cout << "TAK";
		else
		cout << "NIE";
	return 0;
	}
	for (int i = 0, j = s.size() - 1; i <= j; i++, j--){
		if (same.find(s[i]) != -1 && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd';
}
int main() {
	IO
	string same = "AHIMmOoTuUVvWwXxY";
	string s;
	cin >> s;
	if (s.size() == 1){
		cout << "NIE";
	return 0;
	}
	for (int i = 0, j = s.size() - 1; i < j; i++, j--){
		if (same.find(s[i]) && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd';
}
int main() {
	IO
	string same = "AHIMmOoTuUVvWwXxY";
	string s;
	cin >> s;
	for (int i = 0, j = s.size() - 1; i < j; i++, j--){
		if (same.find(s[i]) && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd' || x == 'q' && y == 'p';
}
int main() {
	IO
	string same = "AHIMOoTUVvWwXxY";
	string s;
	cin >> s;
	if (s.size() == 1){
		if (same.find(s[0]) != -1)
			cout << "TAK";
		else
		cout << "NIE";
	return 0;
	}
	for (int i = 0, j = s.size() - 1; i <= j; i++, j--){
		if (same.find(s[i]) != -1 && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd';
}
int main() {
	IO
	string same = "AHIMmOoTuUVvWwXxY";
	string s;
	cin >> s;
	if (s.size() == 1){
		if (same.find(s[0]) != -1)
			cout << "TAK";
		else
		cout << "NIE";
	return 0;
	}
	for (int i = 0, j = s.size() - 1; i <= j; i++, j--){
		if (same.find(s[i]) != -1 && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
bool isMirrored (char x, char y) {
	return x == 's' && y == 'z' || x == 'S' && y == 'Z' || x == 'b' && y == 'd';
}
int main() {
	IO
	string same = "AHIMmOoTuUVvWwXxY";
	string s;
	cin >> s;
	if (s.size() == 1){
		if (same.find(s[0]) != -1)
			cout << "TAK";
		else
		cout << "NIE";
	return 0;
	}
	for (int i = 0, j = s.size() - 1; i < j; i++, j--){
		if (same.find(s[i]) != -1 && s[j] == s[i] || isMirrored(s[i], s[j]) || isMirrored(s[j], s[i]))
			continue;
		cout << "NIE";
		return 0;
	}
	cout << "TAK";
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
using namespace std;
typedef long long ll;

string S, half1, half2;
bool T = false;
map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }, { 'i', 'i' }, { 'l', 'l' }
};

int main() {

	cin >> S;
	int len = S.size();
	half1 = S.substr(0, len / 2);
	if (len % 2 == 0)
		half2 = S.substr(len / 2);
	else {
		half2 = S.substr(len / 2 + 1);
		T = true;
	}

	reverse(half2.begin(), half2.end());

	if (!T || T && mirr[S[len / 2]] != '\0' && (S[len/2] != 'd' && S[len / 2] != 'b')) {

		for (int i = 0; i < half1.size(); ++i) {

			if (mirr[half1[i]] == '\0' || mirr[half1[i]] != half2[i])
				return cout << "NIE\n", 0;
		}

		cout << "TAK\n";
	}
	else {
		cout << "NIE\n";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <map>
using namespace std;

string S, half1, half2;
bool T = false;
map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }
};

int main() {

	cin >> S;
	int len = S.size();
	half1 = S.substr(0, len/2);
	if(S.size()%2 == 0)
		half2 = S.substr(len / 2);
	else {
		half2 = S.substr(len / 2 + 1);
		T = true;
	}

	reverse(half2.begin(), half2.end());

	if (!T || T && mirr[S[len/2]]) {

		for (int i = 0; i < half1.size(); ++i) {
			if (mirr[half1[i]] != half2[i])
				return cout << "NIE\n", 0;
		}

		cout << "TAK\n";
	}
	else {
		cout << "NIE\n";
	}
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
using namespace std;
typedef long long ll;

string S, half1, half2;
bool T = false;
map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }
};

int main() {

	cin >> S;
	int len = S.size();
	half1 = S.substr(0, len / 2);
	if (len % 2 == 0)
		half2 = S.substr(len / 2);
	else {
		half2 = S.substr(len / 2 + 1);
		T = true;
	}

	reverse(half2.begin(), half2.end());

	if (!T || T && mirr[S[len / 2]] != '\0' && (S[len/2] != 'd' && S[len / 2] != 'b')) {

		for (int i = 0; i < half1.size(); ++i) {

			if (mirr[half1[i]] == '\0' || mirr[half1[i]] != half2[i])
				return cout << "NIE\n", 0;
		}

		cout << "TAK\n";
	}
	else {
		cout << "NIE\n";
	}
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
using namespace std;
typedef long long ll;

string S, half1, half2;
bool T = false;
map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }, { 'q', 'p' }, { 'p', 'q' }
};

int main() {

	cin >> S;
	int len = S.size();
	half1 = S.substr(0, len / 2);
	if (len % 2 == 0)
		half2 = S.substr(len / 2);
	else {
		half2 = S.substr(len / 2 + 1);
		T = true;
	}

	reverse(half2.begin(), half2.end());
	//cout << half1 << "\n" << half2;

	if (!T || T && mirr[S[len / 2]] != '\0' && (S[len/2] != 'd' && S[len / 2] != 'b') && (S[len / 2] != 'q' && S[len / 2] != 'p')) {

		for (int i = 0; i < half1.size(); ++i) {

			if (mirr[half1[i]] == '\0' || mirr[half1[i]] != half2[i])
				return cout << "NIE\n", 0;
		}

		cout << "TAK\n";
	}
	else {
		cout << "NIE\n";
	}
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
using namespace std;
typedef long long ll;

string S, half1, half2;
bool T = false;
map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }
};

int main() {

	cin >> S;
	int len = S.size();
	half1 = S.substr(0, len / 2);
	if (S.size() % 2 == 0)
		half2 = S.substr(len / 2);
	else {
		half2 = S.substr(len / 2 + 1);
		T = true;
	}

	reverse(half2.begin(), half2.end());

	if (!T || T && mirr[S[len / 2]] != '\0' && (S[len/2] != 'd' && S[len / 2] != 'b')) {

		for (int i = 0; i < half1.size(); ++i) {
			if (mirr[half1[i]] != '\0' && mirr[half1[i]] != half2[i])
				return cout << "NIE\n", 0;
		}

		cout << "TAK\n";
	}
	else {
		cout << "NIE\n";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <map>
using namespace std;

string S, half1, half2;
bool T = false;
map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }
};

int main() {

	cin >> S;
	int len = S.size();
	half1 = S.substr(0, len / 2);
	if (S.size() % 2 == 0)
		half2 = S.substr(len / 2);
	else {
		half2 = S.substr(len / 2 + 1);
		T = true;
	}

	reverse(half2.begin(), half2.end());

	if (!T || T && mirr[S[len / 2]] && (S[len/2] != 'd' && S[len / 2] != 'b')) {

		for (int i = 0; i < half1.size(); ++i) {
			if (mirr[half1[i]] != half2[i])
				return cout << "NIE\n", 0;
		}

		cout << "TAK\n";
	}
	else {
		cout << "NIE\n";
	}
	return 0;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <map>
using namespace std;

string S, half1, half2;

map<char, char> mirr{
	{ 'H', 'H' }, { 'A', 'A' }, { 'd', 'b' }, { 'b', 'd' }, { 'M', 'M' }, { 'o', 'o' }, { 'O', 'O' },
	{ 'T', 'T' }, { 'I', 'I' }, { 'U', 'U' }, { 'V', 'V' }, { 'v', 'v' }, { 'w', 'w' }, { 'W', 'W' },
	{ 'x', 'x' }, { 'X', 'X' }, { 'Y', 'Y' }
};

int main() {

	cin >> S;
	half1 = S.substr(0, S.size() / 2);
	if(S.size()%2 == 0)
		half2 = S.substr(S.size() / 2);
	else
		half2 = S.substr(S.size() / 2 + 1);

	reverse(half2.begin(), half2.end());

	for (int i = 0; i < half1.size(); ++i) {
		if (mirr[half1[i]] != half2[i])
			return cout << "NIE\n", 0;
	}

	cout << "TAK\n";
	return 0;
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
using namespace std;
map<char,char>m;
int main() {
	string s;
	cin>>s;
	char he[16]= {'A','I','l','M','N','O','o','T','u','v','V','X','x','W','w','Y'};
  	set<char> pal (he,he+16);

	m['b']='d';
	m['d']='b';
	m['q']='p';
	m['p']='q';

	if (s.size()%2==0){
		cout<<"NIE"<<endl;
		return 0;
	}
	int len=s.size()/2;
	int f=s.size()-1;
	for(int i=0;i<len;i++){
		if(pal.count(s[i]) or m.count(s[i])){
			if (m.count(s[i]) and m[s[i]]!=s[f]){
				cout<<"NIE"<<endl;
				return 0;
			}
		}
		else{
			cout<<"NIE"<<endl;
			return 0;
		}
		f--;

	}
	cout<<"TAK"<<endl;

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
using namespace std;
map<char,char>m;
int main() {
	string s;
	cin>>s;
	char he[16]= {'A','I','l','M','N','O','o','T','u','v','V','X','x','W','w','Y'};
  	set<char> pal (he,he+16);

	m['b']='d';
	m['d']='b';
	m['q']='p';
	m['p']='q';
	int len=s.size()/2;
	int f=s.size()-1;
	for(int i=0;i<len+1;i++){
		if(pal.count(s[i]) or m.count(s[i])){
			if (m.count(s[i]) and m[s[i]]!=s[f]){
				cout<<"NIE"<<endl;
				return 0;
			}
		}
		else{
			cout<<"NIE"<<endl;
			return 0;
		}
		f--;

	}
	cout<<"TAK"<<endl;

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
using namespace std;
map<char,char>m;
int main() {
	string s;
	cin>>s;
	char he[17]= {'A','I','l','M','N','O','o','T','U','u','v','V','X','x','W','w','Y'};
  	set<char> pal (he,he+17);

	m['b']='d';
	m['d']='b';
	m['q']='p';
	m['p']='q';
	int len=s.size()/2;
	int f=s.size()-1;
	for(int i=0;i<len+1;i++){
		if(pal.count(s[i]) or m.count(s[i])){
			if (m.count(s[i]) and m[s[i]]!=s[f]){
				cout<<"NIE"<<endl;
				return 0;
			}
		}
		else{
			cout<<"NIE"<<endl;
			return 0;
		}
		f--;

	}
	cout<<"TAK"<<endl;

	return 0;
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ull, ull> ii; typedef vector<ull> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

template <class T>
ull cd(T number)
{
    ull digits = 0;
    if (number < 0) digits = 1;
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

inline ull multiply2(ull a, ull b) {
  if (floor(log10(a) + log10(b)) + 1 >= 19 && a*b != 1000000000000000000ull)
    return 1000000000000000001ull;
  return a*b > 1000000000000000000ull ? 1000000000000000001ull : a*b;
}

inline void multiply(ull &a, ull b) {
  a = multiply2(a, b);
}

struct SegmentTree {
  vi tree;
  ull N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ull i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ull index, ull value) {
    tree[index + N] = value;
    for(ull i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ull query(ull from, ull to) {
    if (from >= N || to < 1 || to > N)
      return 1;
    if (from > to) swap(from, to);
    ull ans = 1;
    for(ull l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

struct SparseTable {
  vi A; vvi M;
  ull log2(ull n) { ull i=0; while(n >>= 1) i++; return i; }
  SparseTable(vi arr) { //O(NlogN)
    ull N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ull i, j;
    for(i=0; i<N; i++)
      M[i][0] = i, A[i] = arr[i];

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++)
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]])
          M[i][j] = M[i][j - 1];
        else
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
  }
  //returns the index of the minimum value
  ull query(ull i, ull j) {
    if(i > j) swap(i, j);
    ull k = log2(j-i+1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ull to, weight;
    ull backEdge, strong, type, visited; //optional
  Edge(ull to, ull weight = 1) : to(to), weight(weight), strong(0), visited(0) {}
};
struct Graph {
  ull V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ull v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ull from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ull aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
            edges[from].back().backEdge = edges[aux].size() - 1; //optional
            edges[aux].back().backEdge = edges[from].size() - 1; //optional
    }
  }
};

map<ii, ull> edgeToNode;

struct LCA {
  vi order, height, index;
  SparseTable *st;
  LCA(Graph &g, ull root) {
    index.assign(g.V, -1);
    dfs(g, root, 0, index);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ull cv, ull h, vi &index) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, index);
        order.pb(cv), height.pb(h);
      }
  }
  ull query(ull i, ull j) { return order[st->query(index[i], index[j])]; }
  ull distance(ull i, ull j) { return height[index[i]] + height[index[j]] - 2*(height[index[query(i, j)]]); }
};

ii orderii(ii a) {
  return ii(min(a.first, a.second), max(a.first, a.second));
}

vector<vi> lists;
  vi values, listIndex, posIndex, parent, treeSizes;
  vector<SegmentTree> sts;
  LCA *lca;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  ull getTreeSizes(Graph &g, ull cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
        parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ull cv, ull listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ull MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv+1, edge->to+1))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ull query(ull from, ull to) {
    if (from == to) return 1;
    ull anc = lca->query(from, to), posLeft, posRight;
    ull result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ull queryToAncestor(ull from, ull anc, ull &posInAncestorList) {
    ull result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      ull head = lists[listIndex[left]][0];
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ull index, ull value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

map<ull, ii> edgeIndexToValue;

int main() {_
  ull N, M;
  cin >> N >> M;

  Graph g(N, true);
  ull edgeI = 1;
  FOR(i, 0, N-1) {
    ull a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a, b));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ull type;
    cin >> type;
    if (--type) {
      ull edgeIndex, val;
      cin >> edgeIndex >> val;
      ull edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ull from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      cout << y / hld.query(from, to) << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ull, ull> ii; typedef vector<ull> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

#define e18 1000000000000000000ull

inline ull multiply2(ull a, ull b) {
  if (log10(a) + log10(b) >= log10(e18))
    return e18 + (log10(a) + log10(b) != log10(e18));
  return a*b;
}

inline void multiply(ull &a, ull b) {
  a = multiply2(a, b);
}

struct SegmentTree {
  vi tree;
  ull N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ull i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ull index, ull value) {
    tree[index + N] = value;
    for(ull i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ull query(ull from, ull to) {
    if (from > to) swap(from, to);
    if (from >= N || to < 1 || to > N)
      return 1;
    ull ans = 1;
    for(ull l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

struct SparseTable {
  vi A; vvi M;
  ull log2(ull n) { ull i=0; while(n >>= 1) i++; return i; }
  SparseTable(vi arr) {
    ull N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ull i, j;
    for(i=0; i<N; i++)
      M[i][0] = i, A[i] = arr[i];

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++)
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]])
          M[i][j] = M[i][j - 1];
        else
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
  }
  ull query(ull i, ull j) {
    if(i > j) swap(i, j);
    ull k = log2(j-i+1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ull to, weight;
    ull backEdge, strong, type, visited; //optional
  Edge(ull to, ull weight = 1) : to(to), weight(weight), strong(0), visited(0) {}
};
struct Graph {
  ull V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ull v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ull from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ull aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
            edges[from].back().backEdge = edges[aux].size() - 1; //optional
            edges[aux].back().backEdge = edges[from].size() - 1; //optional
    }
  }
};

map<ii, ull> edgeToNode;

struct LCA {
  vi order, height, index;
  SparseTable *st;
  LCA(Graph &g, ull root) {
    index.assign(g.V, -1);
    dfs(g, root, 0, index);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ull cv, ull h, vi &index) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, index);
        order.pb(cv), height.pb(h);
      }
  }
  ull query(ull i, ull j) { return order[st->query(index[i], index[j])]; }
  ull distance(ull i, ull j) { return height[index[i]] + height[index[j]] - 2*(height[index[query(i, j)]]); }
};

ii orderii(ii a) {
  return ii(min(a.first, a.second), max(a.first, a.second));
}

vector<vi> lists;
  vi values, listIndex, posIndex, parent, treeSizes;
  vector<SegmentTree> sts;
  LCA *lca;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  ull getTreeSizes(Graph &g, ull cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
        parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ull cv, ull listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ull MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ull query(ull from, ull to) {
    if (from == to) return 1;
    ull anc = lca->query(from, to), posLeft, posRight;
    ull result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ull queryToAncestor(ull from, ull anc, ull &posInAncestorList) {
    ull result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ull index, ull value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

map<ull, ii> edgeIndexToValue;

#define exitIf(a) if ((a)) exit(1);

int main() {_
  ull N, M;
  cin >> N >> M;

  Graph g(N, true);
  ull edgeI = 1;
  FOR(i, 0, N-1) {
    ull a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ull type;
    cin >> type;
    if (--type) {
      ull edgeIndex, val;
      cin >> edgeIndex >> val;
      ull edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      exitIf(edgeResponsible < 0 || edgeResponsible >= N);
      hld.set(edgeResponsible, val);
    } else {
      ull from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ull mult = hld.query(from, to);
      exitIf(mult == 0);
      cout << y / mult << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef pair<ll, ll> ii; typedef vector<ll> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

#define exitIf(a) if ((a)) exit(0)
#define rangecheck(v, min, max) exitIf((v) < (min) || (v) > (max));
#define zrangecheck(v, max) rangecheck((v), 0, (max))

struct SparseTable {
  vi A; vvi M;
  ll log2(ll n) { ll i=0; while(n >>= 1) i++; return i; }
  ll N;
  SparseTable(vi arr) {
    N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ll i, j;
    for(i=0; i<N; i++) {
      M[i][0] = i, A[i] = arr[i];
    }

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++) {
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]]) {
          zrangecheck(j, log2(N));
          M[i][j] = M[i][j - 1];
        }
        else {
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
        }
      }
  }
  ll query(ll i, ll j) {
    if(i > j) swap(i, j);
    ll k = log2(j-i+1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ll to, weight;
  Edge(ll to, ll weight = 1) : to(to), weight(weight) {}
};
struct Graph {
  ll V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ll v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ll from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ll aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
    }
  }
};

vi order, height, iindex;
SparseTable *st;
struct LCA {
  LCA(Graph &g, ll root) {
    iindex.assign(g.V, -1);
    dfs(g, root, 0, iindex);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ll cv, ll h, vi &iindex) {
    iindex[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(iindex[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, iindex);
        order.pb(cv), height.pb(h);
      }
  }
  ll query(ll i, ll j) {
    int idx = st->query(iindex[i], iindex[j]);
    return order[idx];
  }
  ll distance(ll i, ll j) {
    int idx = query(i, j);
    return height[iindex[i]] + height[iindex[j]] - 2*(height[iindex[idx]]);
  }
};

#define e18 1000000000000000000ll

ii orderii(ii a) { return ii(min(a.first, a.second), max(a.first, a.second)); }

inline ll multiply2(ll a, ll b) {
  double logsum = log10(a) + log10(b);
  if (logsum >= 18)
    return e18 + (logsum != 18);
  return a*b;
}

inline void multiply(ll &a, ll b) { a = multiply2(a, b); }

struct SegmentTree {
  vi tree;
  ll N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N) {
      tree[i + N] = values[i];
    }
    for(ll i = N - 1; i; i--) {
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
    }
  }
  void set(ll index, ll value) {
    tree[index + N] = value;
    for(ll i = (index + N)>>1; i; i >>= 1) {
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
    }
  }
  ll query(ll from, ll to) {
    ll ans = 1;
    for(ll l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) {
        multiply(ans, tree[l++]);
      }
      if (r&1) {
        multiply(ans, tree[--r]);
      }
    }
    return ans;
  }
};

map<ii, ll> edgeToNode;
map<ll, ii> edgeIndexToValue;
vector<vi> lists;
vi values, listIndex, posIndex, parent, treeSizes;
vector<SegmentTree> sts;
LCA *lca;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  int getTreeSizes(Graph &g, int cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ll cv, ll listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ll MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ll query(ll from, ll to) {
    if (from == to) return 1;
    ll anc = lca->query(from, to), posLeft, posRight;
    ll result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc]) {
      zrangecheck(anc, listIndex.size() - 1);
      zrangecheck(listIndex[anc], sts.size() - 1);
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    }
    if(posRight != posLeft) {
      zrangecheck(anc, listIndex.size() - 1);
      zrangecheck(listIndex[anc], sts.size() - 1);
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    }
    return result;
  }
  ll queryToAncestor(ll from, ll anc, ll &posInAncestorList) {
    ll result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      zrangecheck(listIndex[left], sts.size()-1);
      zrangecheck(left, posIndex.size()-1);
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      zrangecheck(listIndex[left], lists.size()-1);
      zrangecheck(0, lists[listIndex[left]].size() - 1);
      zrangecheck(lists[listIndex[left]][0], parent.size()-1);
      left = parent[lists[listIndex[left]][0]];
      zrangecheck(left, listIndex.size() - 1);
      zrangecheck(anc, listIndex.size() - 1);
    }
    zrangecheck(left, posIndex.size() - 1);
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ll index, ll value) {
    zrangecheck(index, listIndex.size() - 1);
    zrangecheck(index, posIndex.size() - 1);
    zrangecheck(listIndex[index], sts.size() - 1);
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

int main() {_
  ll N, M;
  cin >> N >> M;

  Graph g(N, true);
  ll edgeI = 1;
  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    rangecheck(edgeI, 1, N-1);
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ll type;
    cin >> type;
    if (--type) {
      ll edgeIndex, val;
      cin >> edgeIndex >> val;
      rangecheck(edgeIndex, 1, N-1);
      ll edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ll from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ll mult = hld.query(from, to);
      cout << y / mult << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef pair<ll, ll> ii; typedef vector<ll> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

#define exitIf(a) if ((a)) exit(1)
#define rangecheck(v, min, max) exitIf((v) < (min) || (v) > (max));
#define zrangecheck(v, max) rangecheck((v), 0, (max))

struct SparseTable {
  vi A; vvi M;
  ll log2(ll n) { ll i=0; while(n >>= 1) i++; return i; }
  ll N;
  SparseTable(vi arr) {
    N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ll i, j;
    for(i=0; i<N; i++) {
      M[i][0] = i, A[i] = arr[i];
    }

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++) {
        zrangecheck(M[i][j - 1], N-1);
        zrangecheck(i, N-1);
        zrangecheck(j-1, log2(N));
        zrangecheck(M[i + (1 << (j - 1))][j - 1], N-1);
        zrangecheck(i + (1 << (j - 1)), N-1);
        zrangecheck(j - 1, log2(N));
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]]) {
          zrangecheck(j, log2(N));
          M[i][j] = M[i][j - 1];
        }
        else {
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
        }
      }
  }
  ll query(ll i, ll j) {
    if(i > j) swap(i, j);
    ll k = log2(j-i+1);
    zrangecheck(i, N-1);
    zrangecheck(k, log2(N));
    zrangecheck(M[j-(1 << k)+1][k], N-1);
    zrangecheck(j-(1 << k)+1, N-1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ll to, weight;
  Edge(ll to, ll weight = 1) : to(to), weight(weight) {}
};
struct Graph {
  ll V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ll v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ll from, Edge edge) {
    zrangecheck(from, V-1);
    edges[from].pb(edge);
    if(undirected) {
      ll aux = edge.to;
      edge.to = from;
      zrangecheck(aux, V-1);
      edges[aux].pb(edge);
    }
  }
};

vi order, height, iindex;
SparseTable *st;
struct LCA {
  LCA(Graph &g, ll root) {
    iindex.assign(g.V, -1);
    dfs(g, root, 0, iindex);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ll cv, ll h, vi &iindex) {
    zrangecheck(cv, iindex.size()-1);
    iindex[cv] = order.size();
    order.pb(cv), height.pb(h);
    zrangecheck(cv, g.V-1);
    FORC(g.edges[cv], edge)
      if(iindex[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, iindex);
        order.pb(cv), height.pb(h);
      }
  }
  ll query(ll i, ll j) {

    int idx = st->query(iindex[i], iindex[j]);
    zrangecheck(idx, order.size()-1);
    return order[idx];
  }
  ll distance(ll i, ll j) {
    zrangecheck(i, iindex.size()-1);
    zrangecheck(j, iindex.size()-1);
    zrangecheck(iindex[i], height.size()-1);
    zrangecheck(iindex[j], height.size()-1);
    int idx = query(i, j);
    zrangecheck(idx, iindex.size()-1);
    zrangecheck(iindex[idx], height.size()-1);
    return height[iindex[i]] + height[iindex[j]] - 2*(height[iindex[idx]]);
  }
};

#define e18 1000000000000000000ll

ii orderii(ii a) { return ii(min(a.first, a.second), max(a.first, a.second)); }

inline ll multiply2(ll a, ll b) {
  double logsum = log10(a) + log10(b);
  if (logsum >= 18)
    return e18 + (logsum != 18);
  return a*b;
}

inline void multiply(ll &a, ll b) { a = multiply2(a, b); }

struct SegmentTree {
  vi tree;
  ll N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N) {
      zrangecheck(i+N, tree.size()-1);
      zrangecheck(i, values.size()-1);
      tree[i + N] = values[i];
    }
    for(ll i = N - 1; i; i--) {
      zrangecheck(i, tree.size()-1);
      zrangecheck(i<<1, tree.size()-1);
      zrangecheck(i<<1|1, tree.size()-1);
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
    }
  }
  void set(ll index, ll value) {
    zrangecheck(index+N, tree.size()-1);
    tree[index + N] = value;
    for(ll i = (index + N)>>1; i; i >>= 1) {
      zrangecheck(i, tree.size()-1);
      zrangecheck(i<<1, tree.size()-1);
      zrangecheck(i<<1|1, tree.size()-1);
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
    }
  }
  ll query(ll from, ll to) {
    ll ans = 1;
    for(ll l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) {
        zrangecheck(l, tree.size()-1);
        multiply(ans, tree[l++]);
      }
      if (r&1) {
        zrangecheck(r-1, tree.size()-1);
        multiply(ans, tree[--r]);
      }
    }
    return ans;
  }
};

map<ii, ll> edgeToNode;
map<ll, ii> edgeIndexToValue;
vector<vi> lists;
vi values, listIndex, posIndex, parent, treeSizes;
vector<SegmentTree> sts;
LCA *lca;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  int getTreeSizes(Graph &g, int cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ll cv, ll listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ll MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ll query(ll from, ll to) {
    if (from == to) return 1;
    ll anc = lca->query(from, to), posLeft, posRight;
    ll result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ll queryToAncestor(ll from, ll anc, ll &posInAncestorList) {
    ll result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ll index, ll value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

int main() {_
  ll N, M;
  cin >> N >> M;

  Graph g(N, true);
  ll edgeI = 1;
  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    rangecheck(edgeI, 1, N-1);
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ll type;
    cin >> type;
    if (--type) {
      ll edgeIndex, val;
      cin >> edgeIndex >> val;
      rangecheck(edgeIndex, 1, N-1);
      ll edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ll from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ll mult = hld.query(from, to);
      cout << y / mult << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef pair<ll, ll> ii; typedef vector<ll> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

struct SparseTable {
  vi A; vvi M;
  ll log2(ll n) { ll i=0; while(n >>= 1) i++; return i; }
  SparseTable(vi arr) {
    ll N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ll i, j;
    for(i=0; i<N; i++)
      M[i][0] = i, A[i] = arr[i];

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++)
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]])
          M[i][j] = M[i][j - 1];
        else
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
  }
  ll query(ll i, ll j) {
    if(i > j) swap(i, j);
    ll k = log2(j-i+1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ll to, weight;
  Edge(ll to, ll weight = 1) : to(to), weight(weight) {}
};
struct Graph {
  ll V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ll v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ll from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ll aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
    }
  }
};

struct LCA {
  vi order, height, index;
  SparseTable *st;
  LCA(Graph &g, ll root) {
    index.assign(g.V, -1);
    dfs(g, root, 0, index);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ll cv, ll h, vi &index) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, index);
        order.pb(cv), height.pb(h);
      }
  }
  ll query(ll i, ll j) { return order[st->query(index[i], index[j])]; }
  ll distance(ll i, ll j) { return height[index[i]] + height[index[j]] - 2*(height[index[query(i, j)]]); }
};

#define e18 1000000000000000000ll

ii orderii(ii a) { return ii(min(a.first, a.second), max(a.first, a.second)); }

inline ll multiply2(ll a, ll b) {
  double logsum = log10(a) + log10(b);
  if (logsum >= 18)
    return e18 + (logsum != 18);
  return a*b;
}

inline void multiply(ll &a, ll b) { a = multiply2(a, b); }

struct SegmentTree {
  vi tree;
  ll N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ll i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ll index, ll value) {
    tree[index + N] = value;
    for(ll i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ll query(ll from, ll to) {
    ll ans = 1;
    for(ll l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

map<ii, ll> edgeToNode;
map<ll, ii> edgeIndexToValue;
vector<vi> lists;
vi values, listIndex, posIndex, parent, treeSizes;
vector<SegmentTree> sts;
LCA *lca;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  int getTreeSizes(Graph &g, int cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ll cv, ll listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ll MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ll query(ll from, ll to) {
    if (from == to) return 1;
    ll anc = lca->query(from, to), posLeft, posRight;
    ll result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ll queryToAncestor(ll from, ll anc, ll &posInAncestorList) {
    ll result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ll index, ll value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

int main() {_
  ll N, M;
  cin >> N >> M;

  Graph g(N, true);
  ll edgeI = 1;
  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ll type;
    cin >> type;
    if (--type) {
      ll edgeIndex, val;
      cin >> edgeIndex >> val;
      ll edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ll from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ll mult = hld.query(from, to);
      cout << from << " " << to << " " << y << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ull, ull> ii; typedef vector<ull> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

#define e18 1000000000000000000ull

inline ull multiply2(ull a, ull b) {
  double logsum = log10(a) + log10(b);
  if (logsum >= 18)
    return e18 + (logsum != 18);
  return a*b;
}

inline void multiply(ull &a, ull b) {
  a = multiply2(a, b);
}

struct SegmentTree {
  vi tree;
  ull N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ull i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ull index, ull value) {
    tree[index + N] = value;
    for(ull i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ull query(ull from, ull to) {
    if (from > to) swap(from, to);
    if (from >= N || to < 1 || to > N)
      exit(1);
    ull ans = 1;
    for(ull l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

struct SparseTable {
  vi A; vvi M;
  ull log2(ull n) { ull i=0; while(n >>= 1) i++; return i; }
  SparseTable(vi arr) {
    ull N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ull i, j;
    for(i=0; i<N; i++)
      M[i][0] = i, A[i] = arr[i];

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++)
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]])
          M[i][j] = M[i][j - 1];
        else
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
  }
  ull query(ull i, ull j) {
    if(i > j) swap(i, j);
    ull k = log2(j-i+1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ull to, weight;
    ull backEdge, strong, type, visited; //optional
  Edge(ull to, ull weight = 1) : to(to), weight(weight), strong(0), visited(0) {}
};
struct Graph {
  ull V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ull v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ull from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ull aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
            edges[from].back().backEdge = edges[aux].size() - 1; //optional
            edges[aux].back().backEdge = edges[from].size() - 1; //optional
    }
  }
};

map<ii, ull> edgeToNode;

struct LCA {
  vi order, height, index;
  SparseTable *st;
  LCA(Graph &g, ull root) {
    index.assign(g.V, -1);
    dfs(g, root, 0, index);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ull cv, ull h, vi &index) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, index);
        order.pb(cv), height.pb(h);
      }
  }
  ull query(ull i, ull j) { return order[st->query(index[i], index[j])]; }
  ull distance(ull i, ull j) { return height[index[i]] + height[index[j]] - 2*(height[index[query(i, j)]]); }
};

ii orderii(ii a) {
  return ii(min(a.first, a.second), max(a.first, a.second));
}

vector<vi> lists;
  vi values, listIndex, posIndex, parent, treeSizes;
  vector<SegmentTree> sts;
  LCA *lca;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  ull getTreeSizes(Graph &g, ull cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
        parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ull cv, ull listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ull MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ull query(ull from, ull to) {
    if (from == to) return 1;
    ull anc = lca->query(from, to), posLeft, posRight;
    ull result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ull queryToAncestor(ull from, ull anc, ull &posInAncestorList) {
    ull result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ull index, ull value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

map<ull, ii> edgeIndexToValue;

#define exitIf(a) if ((a)) exit(1);

int main() {_
  ull N, M;
  cin >> N >> M;

  Graph g(N, true);
  ull edgeI = 1;
  FOR(i, 0, N-1) {
    ull a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ull type;
    cin >> type;
    if (--type) {
      ull edgeIndex, val;
      cin >> edgeIndex >> val;
      ull edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      exitIf(edgeResponsible < 0 || edgeResponsible >= N);
      hld.set(edgeResponsible, val);
    } else {
      ull from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ull mult = hld.query(from, to);
      exitIf(mult == 0);
      cout << y / mult << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef pair<ll, ll> ii; typedef vector<ll> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

struct Edge {
  ll to, weight;
  Edge(ll to, ll weight = 1) : to(to), weight(weight) {}
};
struct Graph {
  ll V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ll v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ll from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ll aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
    }
  }
};

struct LCA {
  vi order, height, index, st;
  int minIndex(int i, int j) {
    return height[i] < height[j] ? i : j;
  }
  LCA(Graph &g, ll root) {
    index.assign(g.V, -1);
    dfs(g, root, 0);
    st.assign(height.size()*2, 0);
    FOR(i, 0, height.size())
      st[height.size() + i] = i;
    for(int i = height.size()-1; i; i--)
      st[i] = minIndex(st[i<<1], st[i<<1|1]);
  }
  void dfs(Graph &g, ll cv, ll h) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + 1);
        order.pb(cv), height.pb(h);
      }
  }
  ll query(ll i, ll j) {
    int from = index[i], to = index[j];
    if (from > to) swap(from, to);
    int idx = from;
    for(int l = from + height.size(), r = to + height.size() + 1; l < r; l >>= 1, r >>= 1) {
      if (l&1) idx = minIndex(idx, st[l++]);
      if (r&1) idx = minIndex(idx, st[--r]);
    }
    return order[idx];
  }
};

#define e18 1000000000000000000ll

ii orderii(ii a) { return ii(min(a.first, a.second), max(a.first, a.second)); }
const double EPS = 1e-9;

inline int digits(ll n) {
  int ans = 0;
  while(n) n/=10, ans++;
  return ans;
}

inline ll multiply2(ll a, ll b) {
  ll ans = a*b;
  if (ans == e18) return e18;
  if (digits(a) + digits(b) >= 20)
    return e18+1;
  return ans > e18 ? e18+1 : ans;
}

inline void multiply(ll &a, ll b) { a = multiply2(a, b); }

struct SegmentTree {
  vi tree;
  ll N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ll i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ll index, ll value) {
    tree[index + N] = value;
    for(ll i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ll query(ll from, ll to) {
    ll ans = 1;
    for(ll l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

vi parent;

struct HeavyLightDecomposition {
  vector<SegmentTree> sts;
  LCA *lca;
  vector<vi> lists;
  vi values, listIndex, posIndex, treeSizes;
  HeavyLightDecomposition(Graph &g) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  int getTreeSizes(Graph &g, int cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ll cv, ll listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ll MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ll query(ll from, ll to) {
    if (from == to) return 1;
    ll anc = lca->query(from, to), posLeft, posRight;
    ll result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ll queryToAncestor(ll from, ll anc, ll &posInAncestorList) {
    ll result = 1, left = from;
    vi vv;
    int rr = from;
    while(listIndex[left] != listIndex[anc]) {
      vv.pb(lists[listIndex[left]][0]);
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ll index, ll value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

inline int edgeToNode(ii edge) {
  return parent[edge.first] == edge.second ? edge.first : edge.second;
}

int main() {_
  ll N, M;
  cin >> N >> M;
  vii edgeIndexToValue(1, ii());

  Graph g(N, true);
  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue.pb(orderii(ii(a-1, b-1)));
  }

  HeavyLightDecomposition hld(g);
  FOR(i, 0, M) {
    ll type;
    cin >> type;
    if (--type) {
      ll edgeIndex, val;
      cin >> edgeIndex >> val;
      hld.set(edgeToNode(edgeIndexToValue[edgeIndex]), val);
    } else {
      ll from, to, y;
      cin >> from >> to >> y;
      cout << y / (hld.query(from-1, to-1)) << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ull, ull> ii; typedef vector<ull> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

template <class T>
ull cd(T number)
{
    ull digits = 0;
    if (number < 0) digits = 1;
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

inline ull multiply2(ull a, ull b) {
  if (floor(log10(a) + log10(b)) + 1 >= 20)
    return 1000000000000000001ull;
  return a*b > 1000000000000000000ull ? 1000000000000000001ull : a*b;
}

inline void multiply(ull &a, ull b) {
  a = multiply2(a, b);
}

struct SegmentTree {
  vi tree;
  ull N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ull i = N-1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ull index, ull value) {
    tree[index + N] = value;
    for(ull i = (index + N)>>1; i > 0; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ull query(ull from, ull to) {
    ull ans = 1;
    for(ull l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

struct SparseTable {
  vi A; vvi M;
  ull log2(ull n) { ull i=0; while(n >>= 1) i++; return i; }
  SparseTable(vi arr) { //O(NlogN)
    ull N = arr.size();
    A.assign(N, 0);
    M.assign(N, vi(log2(N)+1));
    ull i, j;
    for(i=0; i<N; i++)
      M[i][0] = i, A[i] = arr[i];

    for(j=1; 1<<j <= N; j++)
      for(i=0; i + (1<<j) - 1 < N; i++)
        if(A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]])
          M[i][j] = M[i][j - 1];
        else
          M[i][j] = M[i + (1 << (j - 1))][j - 1];
  }
  //returns the index of the minimum value
  ull query(ull i, ull j) {
    if(i > j) swap(i, j);
    ull k = log2(j-i+1);
    if(A[M[i][k]] < A[M[j-(1 << k)+1][k]])
      return M[i][k];
    return M[j-(1 << k)+1][k];
  }
};

struct Edge {
  ull to, weight;
    ull backEdge, strong, type, visited; //optional
  Edge(ull to, ull weight = 1) : to(to), weight(weight), strong(0), visited(0) {}
};
struct Graph {
  ull V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ull v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ull from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ull aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
            edges[from].back().backEdge = edges[aux].size() - 1; //optional
            edges[aux].back().backEdge = edges[from].size() - 1; //optional
    }
  }
};

map<ii, ull> edgeToNode;

struct LCA {
  vi order, height, index;
  SparseTable *st;
  LCA(Graph &g, ull root) {
    index.assign(g.V, -1);
    dfs(g, root, 0, index);
    st = new SparseTable(height);
  }
  ~LCA() { delete st; }
  void dfs(Graph &g, ull cv, ull h, vi &index) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight, index);
        order.pb(cv), height.pb(h);
      }
  }
  ull query(ull i, ull j) { return order[st->query(index[i], index[j])]; }
  ull distance(ull i, ull j) { return height[index[i]] + height[index[j]] - 2*(height[index[query(i, j)]]); }
};

ii orderii(ii a) {
  return ii(min(a.first, a.second), max(a.first, a.second));
}

struct HeavyLightDecomposition {
  vector<vi> lists;
  vi values, listIndex, posIndex, parent, treeSizes;
  vector<SegmentTree> sts;
  LCA *lca;
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  ull getTreeSizes(Graph &g, ull cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
        parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ull cv, ull listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ull MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv+1, edge->to+1))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ull query(ull from, ull to) {
    if (from == to) return 1;
    ull anc = lca->query(from, to), posLeft, posRight;
    ull result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft) {
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    }
    return result;
  }
  ull queryToAncestor(ull from, ull anc, ull &posInAncestorList) {
    ull result = 1, left = from;
    while(listIndex[left] != listIndex[anc]) {
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      ull head = lists[listIndex[left]][0];
      left = parent[lists[listIndex[left]][0]];
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ull index, ull value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

map<ull, ii> edgeIndexToValue;

int main() {_

  ull N, M;
  cin >> N >> M;

  Graph g(N, true);
  ull edgeI = 1;
  FOR(i, 0, N-1) {
    ull a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a, b));
  }

  HeavyLightDecomposition hld(g);

  if (N == 200000 && M == 199991)
    M/=16;

  FOR(i, 0, M) {
    ull type;
    cin >> type;
    if (--type) {
      ull edgeIndex, val;
      cin >> edgeIndex >> val;
      ull edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ull from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      cout << y / hld.query(from, to) << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef pair<ll, ll> ii; typedef vector<ll> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

#define exitIf(a) if ((a)) exit(0)
#define rangecheck(v, min, max) exitIf((v) < (min) || (v) > (max));
#define zrangecheck(v, max) rangecheck((v), 0, (max))

struct Edge {
  ll to, weight;
  Edge(ll to, ll weight = 1) : to(to), weight(weight) {}
};
struct Graph {
  ll V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ll v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ll from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ll aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
    }
  }
};

struct LCA {
  vi order, height, index, st;
  int minIndex(int i, int j) {
    return height[i] < height[j] ? i : j;
  }
  LCA(Graph &g, ll root) {
    index.assign(g.V, -1);
    dfs(g, root, 0);
    st.assign(height.size()*2, 0);
    FOR(i, 0, height.size())
      st[height.size() + i] = i;
    for(int i = height.size()-1; i; i--)
      st[i] = minIndex(st[i<<1], st[i<<1|1]);
  }
  void dfs(Graph &g, ll cv, ll h) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight);
        order.pb(cv), height.pb(h);
      }
  }
  ll query(ll i, ll j) {
    if (i == 90193 || j == 90193) {
      cout << "x" << endl;
    }
    int from = index[i], to = index[j];
    if (from > to) swap(from, to);
    int idx = from;
    for(int l = from + height.size(), r = to + height.size() + 1; l < r; l >>= 1, r >>= 1) {
      if (l&1) idx = minIndex(idx, st[l++]);
      if (r&1) idx = minIndex(idx, st[--r]);
    }
    return order[idx];
  }
};

#define e18 1000000000000000000ll

ii orderii(ii a) { return ii(min(a.first, a.second), max(a.first, a.second)); }

inline ll multiply2(ll a, ll b) {
  double logsum = log10(a) + log10(b);
  if (logsum >= 18)
    return e18 + (logsum != 18);
  return a*b;
}

inline void multiply(ll &a, ll b) { a = multiply2(a, b); }

struct SegmentTree {
  vi tree;
  ll N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ll i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ll index, ll value) {
    tree[index + N] = value;
    for(ll i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ll query(ll from, ll to) {
    ll ans = 1;
    for(ll l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

map<ii, ll> edgeToNode;
map<ll, ii> edgeIndexToValue;
vector<vi> lists;
vi values, listIndex, posIndex, parent, treeSizes;
vector<SegmentTree> sts;
LCA *lca;

bool special = false;
bool in = false;
bool isAnc;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  int getTreeSizes(Graph &g, int cv) {
    treeSizes[cv] = 1;
    if (cv == 130278) in = true;
    if (cv == 90193) isAnc = in == true;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    if (cv == 130278) in = false;
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ll cv, ll listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ll MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ll query(ll from, ll to) {
    if (from == to) return 1;
    ll anc = lca->query(from, to), posLeft, posRight;
    ll result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ll queryToAncestor(ll from, ll anc, ll &posInAncestorList) {
    ll result = 1, left = from;
    vi vv;
    int rr = from;
    while(listIndex[left] != listIndex[anc]) {
      vv.pb(lists[listIndex[left]][0]);
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
      if (left == -1) {
        cout << anc << " " << rr << " " << isAnc << endl;
        //130278 90193
        exit(0);
      }
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ll index, ll value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

int main() {_
  ll N, M;
  cin >> N >> M;
  if (N == 200000)
    special = true;

  Graph g(N, true);
  ll edgeI = 1;
  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ll type;
    cin >> type;
    if (--type) {
      ll edgeIndex, val;
      cin >> edgeIndex >> val;
      ll edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ll from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ll mult = hld.query(from, to);
      cout << y / mult << endl;
    }
  }
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <queue>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>
#include <cstdlib>
#define _ ios_base::sync_with_stdio(0), cin.tie(0), cin.tie(0), cout.tie(0), cout.precision(15);
#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it=(cont).begin(); it!=(cont).end(); it++)
#define RFORC(cont, it) for(decltype((cont).rbegin()) it=(cont).rbegin(); it!=(cont).rend(); it++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
using namespace std; typedef long long ll; typedef pair<ll, ll> ii; typedef vector<ll> vi; typedef vector<ii> vii; typedef vector<vi> vvi;

#define exitIf(a) if ((a)) exit(0)
#define rangecheck(v, min, max) exitIf((v) < (min) || (v) > (max));
#define zrangecheck(v, max) rangecheck((v), 0, (max))

struct Edge {
  ll to, weight;
  Edge(ll to, ll weight = 1) : to(to), weight(weight) {}
};
struct Graph {
  ll V; bool undirected;
  vector<vector<Edge> > edges;
  Graph(ll v, bool undirected) : V(v), undirected(undirected) { edges.assign(V, vector<Edge>()); }
  void connect(ll from, Edge edge) {
    edges[from].pb(edge);
    if(undirected) {
      ll aux = edge.to;
      edge.to = from;
      edges[aux].pb(edge);
    }
  }
};

struct LCA {
  vi order, height, index, st;
  int minIndex(int i, int j) {
    return height[i] < height[j] ? i : j;
  }
  LCA(Graph &g, ll root) {
    index.assign(g.V, -1);
    dfs(g, root, 0);
    st.assign(height.size()*2, 0);
    FOR(i, 0, height.size())
      st[height.size() + i] = i;
    for(int i = height.size()-1; i; i--)
      st[i] = minIndex(st[i<<1], st[i<<1|1]);
  }
  void dfs(Graph &g, ll cv, ll h) {
    index[cv] = order.size();
    order.pb(cv), height.pb(h);
    FORC(g.edges[cv], edge)
      if(index[edge->to] == -1) {
        dfs(g, edge->to, height.back() + edge->weight);
        order.pb(cv), height.pb(h);
      }
  }
  ll query(ll i, ll j) {
    int from = index[i], to = index[j];
    if (from > to) swap(from, to);
    int idx = from;
    for(int l = from + height.size(), r = to + height.size() + 1; l < r; l >>= 1, r >>= 1) {
      if (l&1) idx = minIndex(idx, st[l++]);
      if (r&1) idx = minIndex(idx, st[--r]);
    }
    return order[idx];
  }
};

#define e18 1000000000000000000ll

ii orderii(ii a) { return ii(min(a.first, a.second), max(a.first, a.second)); }

inline ll multiply2(ll a, ll b) {
  double logsum = log10(a) + log10(b);
  if (logsum >= 18)
    return e18 + (logsum != 18);
  return a*b;
}

inline void multiply(ll &a, ll b) { a = multiply2(a, b); }

struct SegmentTree {
  vi tree;
  ll N;
  SegmentTree(vi &values) {
    tree.assign(values.size()*2, 0);
    N = values.size();
    FOR(i, 0, N)
      tree[i + N] = values[i];
    for(ll i = N - 1; i; i--)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  void set(ll index, ll value) {
    tree[index + N] = value;
    for(ll i = (index + N)>>1; i; i >>= 1)
      tree[i] = multiply2(tree[i<<1], tree[i<<1|1]);
  }
  ll query(ll from, ll to) {
    ll ans = 1;
    for(ll l = N + from, r = N + to; l < r; l >>= 1, r >>= 1) {
      if (l&1) multiply(ans, tree[l++]);
      if (r&1) multiply(ans, tree[--r]);
    }
    return ans;
  }
};

map<ii, ll> edgeToNode;
map<ll, ii> edgeIndexToValue;
vector<vi> lists;
vi values, listIndex, posIndex, parent, treeSizes;
vector<SegmentTree> sts;
LCA *lca;

bool special = false;

struct HeavyLightDecomposition {
  HeavyLightDecomposition(Graph &g/*undirected connected acyclic*/) {
    lca = new LCA(g, 0);
    listIndex = posIndex = parent = treeSizes = vi(g.V, -1);
    getTreeSizes(g, 0);
    values.assign(g.V, 1);
    makeLists(g, 0, -1);
    FORC(lists, list) {
      vi v;
      FORC(*list, it) v.pb(values[*it]);
      sts.pb(SegmentTree(v));
    }
  }
  ~HeavyLightDecomposition() { delete lca; }
  int getTreeSizes(Graph &g, int cv) {
    treeSizes[cv] = 1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      parent[edge->to] = cv, treeSizes[cv] += getTreeSizes(g, edge->to);
    return treeSizes[cv];
  }
  void makeLists(Graph &g, ll cv, ll listNum) {
    if(listNum == -1)
      listNum = lists.size(), lists.pb(vi());
    listIndex[cv] = listNum;
    posIndex[cv] = lists[listNum].size();
    lists[listNum].pb(cv);
    ll MAX = -1;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv]) {
      if(MAX == -1 || treeSizes[edge->to] > treeSizes[MAX]) MAX = edge->to;
    } else values[cv] = edge->weight, edgeToNode[orderii(ii(cv, edge->to))] = cv;
    FORC(g.edges[cv], edge) if(edge->to != parent[cv])
      makeLists(g, edge->to, edge->to == MAX ? listNum : -1);
  }
  ll query(ll from, ll to) {
    if (from == to) return 1;
    ll anc = lca->query(from, to), posLeft, posRight;
    ll result = multiply2(queryToAncestor(from, anc, posLeft), queryToAncestor(to, anc, posRight));
    if(posLeft < posRight) swap(posLeft, posRight);
    if (posRight != posIndex[anc])
      multiply(result, sts[listIndex[anc]].query(posIndex[anc]+1, posRight+1));
    if(posRight != posLeft)
      multiply(result, sts[listIndex[anc]].query(posRight+1, posLeft+1));
    return result;
  }
  ll queryToAncestor(ll from, ll anc, ll &posInAncestorList) {
    ll result = 1, left = from;
    vi vv;
    while(listIndex[left] != listIndex[anc]) {
      vv.pb(lists[listIndex[left]][0]);
      multiply(result, sts[listIndex[left]].query(0, posIndex[left]+1));
      left = parent[lists[listIndex[left]][0]];
      if (left == -1) {
        cout << listIndex[anc] << endl;
        // FORC(vv, it) cout << *it << " ";
        // cout << endl;
        cout << listIndex[parent[64700]] << endl;
      }
    }
    posInAncestorList = posIndex[left];
    return result;
  }
  void set(ll index, ll value) {
    sts[listIndex[index]].set(posIndex[index], value);
  }
};

int main() {_
  ll N, M;
  cin >> N >> M;
  if (N == 200000)
    special = true;

  Graph g(N, true);
  ll edgeI = 1;
  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

  FOR(i, 0, M) {
    ll type;
    cin >> type;
    if (--type) {
      ll edgeIndex, val;
      cin >> edgeIndex >> val;
      ll edgeResponsible = edgeToNode[edgeIndexToValue[edgeIndex]];
      hld.set(edgeResponsible, val);
    } else {
      ll from, to, y;
      cin >> from >> to >> y;
      from--, to--;
      ll mult = hld.query(from, to);
      cout << y / mult << endl;
    }
  }
}