/*
题目描述:给定一棵树及其边权,有两种操作
1 u v y 用y依次去除uv的公共路径上的每一条边的边权,注意这里的除法是整数的除法
2 x p 把第x条输入边的边权变为p
方法:容易证明,依次去除每一条边权,等于除以这条路径上所有边权的乘积,原因是前者相当于除一次保留一次,后者相当于
每次除完保留小数,最后保留一次,根据这个理论可以证明二者结果相同。
使用树链剖分来处理,维护区间乘积,用long double存,超过1e18就维护成1e18 + 100
*/
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#define LL long long
#define LD long double
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
#define ebp 1000000000000000100LL
#define eb 1000000000000000000.000
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-6;
using namespace std;
const int maxn = 2e5 + 5;
struct Edge
{
int to, next;
}edge[maxn * 2];
int head[maxn], tot;
int top[maxn];//top[v]表示v所在的重链的顶端节点
int fa[maxn]; //父亲节点
int deep[maxn];//深度
int num[maxn];//num[v]表示以v为根的子树的节点数
int p[maxn];//p[v]表示v与其父亲节点的连边在线段树中的位置
int fp[maxn];//和p数组相反
int son[maxn];//重儿子
int from[maxn], to[maxn];
LD t[4 * maxn], w[maxn];
int pos, n;
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
pos = 1;
memset(son, -1, sizeof(son));
}
void addedge(int u, int v)
{
edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++;
}
void dfs1(int u, int pre, int d) //第一遍dfs求出fa,deep,num,son
{
deep[u] = d;
fa[u] = pre;
num[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (v != pre)
{
dfs1(v, u, d + 1);
num[u] += num[v];
if (son[u] == -1 || num[v] > num[son[u]])
son[u] = v;
}
}
}
void getpos(int u, int sp) //第二遍dfs求出top和p
{
top[u] = sp;
if (son[u] != -1)
{
p[u] = pos++;
fp[p[u]] = u;
getpos(son[u], sp);
}
else
{
p[u] = pos++;
fp[p[u]] = u;
return;
}
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (v != son[u] && v != fa[u])
getpos(v, v);
}
}
void pushup(int l, int r, int x)
{
t[x] = t[x << 1] * t[x << 1 | 1];
if (t[x] > eb)
t[x] = eb + 100;
}
void modify(int pos, LD val, int l, int r, int x)
{
if (l == r && pos == l){
t[x] = val;
return;
}
int m = l + (r - l) / 2;
if (pos <= m)
modify(pos, val, lson);
else if (pos > m)
modify(pos, val, rson);
pushup(l, r, x);
}
LD query(int L, int R, int l, int r, int x)
{
if (L == l && R == r){
return t[x];
}
int m = l + (r - l) / 2;
if (R <= m)
return query(L, R, lson);
else if (L > m)
return query(L, R, rson);
else{
LD q1 = query(L, m, lson);
LD q2 = query(m + 1, R, rson);
LD ret = q1 * q2;
if (ret > eb)
return eb + 100;
else
return ret;
}
}
LD find(int u, int v)//查询u->v边的最大值
{
int f1 = top[u], f2 = top[v];
LD tmp = 1.0, Q;
while (f1 != f2)
{
if (deep[f1] < deep[f2])
{
swap(f1, f2);
swap(u, v);
}
Q = query(p[f1], p[u], 1, n, 1);
if (tmp <= eb)
tmp *= Q;
if (tmp > eb) tmp = eb + 100;
u = fa[f1]; f1 = top[u];
}
if (u == v)return tmp;
if (deep[u] > deep[v]) swap(u, v);
Q = query(p[son[u]], p[v], 1, n, 1);
tmp *= Q;
if (tmp > eb) tmp = eb + 100;
return tmp;
}
int main()
{
int m, type, x , y;
LD v1 , v2;
init();
scanf("%d%d", &n, &m);
for (int i = 1; i <= n - 1; i++){
scanf("%d%d%Lf", &from[i], &to[i], &w[i]);
addedge(from[i], to[i]);
addedge(to[i], from[i]);
}
mem(t, 0);
dfs1(1, 1, -1);
getpos(1, 1);
for (int i = 1; i <= n - 1; i++){
if (deep[from[i]] > deep[to[i]])
swap(from[i], to[i]);
modify(p[to[i]], w[i], 1, n, 1);
}
for (int i = 1; i <= m; i++){
scanf("%d", &type);
if (type == 1){
scanf("%d%d%Lf", &x, &y, &v1);
LD Q = find(x, y);
LD res = v1 / Q;
LL ans = res;
printf("%lld\n", ans);
}
else{
scanf("%d%Lf", &x, &v2);
if (deep[from[x]] > deep[to[x]])
swap(from[x], to[x]);
modify(p[to[x]], v2, 1, n, 1);
}
}
return 0;
}