#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*3];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0)
        segTree[i].Max=-1;
    else if(bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
        segTree[i].Max=-1;
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
        return segTree[i].Max;
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<0||holy2<0)
        holy=-1;
        else if(bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {
            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);

    if(tmp<=0||bigg/tmp<holy||holy<=0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao == 0)
                printf("....\n");
                else if(cao<=0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 400005
#define lson l,mid,x<<1
#define rson mid+1,r,x<<1|1
using namespace std;

typedef __int64 ll;
const ll INF = 1000000000000000005;
ll t[maxn*2];
int flag[maxn*2];

struct edge
{
    int y, next, val;
}p[maxn*2];

ll ed[3][maxn], a[maxn];
int son[maxn], top[maxn], size[maxn], dp[maxn], fa[maxn], pos[maxn], sum[maxn], head[maxn];

int qe, n, m, no;

void add(int x, int y)
{
    p[qe].y=y;
    p[qe].next=head[x];
    head[x]=qe++;

    p[qe].y=x;
    p[qe].next=head[y];
    head[y]=qe++;
}

void dfs1( int u, int pre, int dep )
{
    size[u] = 1;
    son[u] = -1;
    fa[u] = pre;
    dp[u] = dep;
    for( int i = head[u]; i >= 0; i = p[i].next ){
        int v = p[i].y;
        if( v == pre )continue;
        dfs1( v, u, dep+1 );
        if( son[u] == -1 || size[son[v]] < size[v] ){
            son[u] = v;
        }
        size[u] += size[v];
    }
}

void dfs2( int u, int tops )
{
    top[u]=tops;
    pos[u]=no++;
    if(son[u]==-1)return;
    dfs2(son[u], tops);
    for(int i=head[u]; i!=-1; i=p[i].next){
        int x=p[i].y;
        if(x==son[u] || x==fa[u] )continue;
        dfs2(x, x);//attention!
    }
}

void build( int l, int r, int x )
{
    if( l == r ){
        t[x] = a[l];
        return;
    }
    int mid = (l+r)/2;
    build( lson );
    build( rson );
    ll tmp = INF/t[x<<1];
    if( tmp <= t[x<<1|1] ) t[x] = INF;
    else t[x] = t[x<<1]*t[x<<1|1];
}

void modify( int T, ll val, int l, int r, int x )
{
    ll tmp;
    if( T == l && l == r ){
        if( val < t[x] ){
            t[x] = val;
        }
        return ;
    }
    int mid = (l+r)>>1;
    if( T <= mid ) modify( T, val, lson );
    else if( T > mid ) modify( T, val, rson );
    tmp = INF/t[x<<1];
    if( tmp <= t[x<<1|1] ) t[x] = INF;
    else t[x] = t[x<<1]*t[x<<1|1];
}

ll query( int L, int R, int l, int r, int x )
{
    ll tmp1, tmp2;
    if( L == l && R == r ){
        return t[x];
    }
    int mid = (l+r)>>1;
    if( R <= mid ) return query( L, R, lson );
    else if( L > mid ) return query( L, R, rson );
    else{
        tmp1 = query( L, mid, lson );
        if( tmp1 >= INF ) return INF;
        tmp2 = query( mid+1, R, rson );
        if( INF/tmp1 <= tmp2 ) return INF;
        else return tmp1*tmp2;
    }
}

ll query(int x, int y)
{
    int f1=top[x], f2=top[y];
    ll tmp;
    ll ans=1;
    while(f1!=f2){
        if(dp[f1]<dp[f2]){
            swap(f1, f2);
            swap(x, y);
        }
        tmp = query( pos[f1], pos[x], 1, no-1, 1);
        if( tmp >= INF ) return INF;
        if( INF/ans <= tmp ) { ans = INF; return INF; }
        else ans = ans*tmp;
        x=fa[f1];
        f1=top[x];
    }
    if( x == y ) return ans;
//    if(x == y){
//        tmp = a[pos[x]];
//        if( INF/ans <= tmp ) { ans = INF; return INF; }
//        else ans = ans*tmp;
//        return ans;
//    }
    if(dp[x]<dp[y])swap(x,y);
    tmp = query(pos[son[y]], pos[x], 1, no-1, 1);
    if( INF/ans <= tmp ) { ans = INF; return INF; }
    else ans = ans*tmp;
    return ans;
}

int main()
{
    int i, j, tmp1, tmp2, x;
    ll num, sum;
    while(~scanf("%d %d", &n, &m)){
        memset( head, -1, sizeof(head));
        no = 1;qe = 0;//no´Ó1¿ªÊ¼±êºÅ
        for( i = 1; i < n; i ++ ){
            scanf("%I64d %I64d %I64d", &ed[0][i], &ed[1][i], &ed[2][i] );
            add(ed[0][i], ed[1][i]);
        }
        dfs1(1, 0 , 1);
        dfs2(1, 1);
        for( i = 1; i < n; i ++ ){
            if( ed[0][i] == fa[ed[1][i]] ){
                a[pos[ed[1][i]]] = ed[2][i];
            }
            else a[pos[ed[0][i]]] = ed[2][i];
        }
        build( 1, no-1, 1 );
        while( m -- ){
           scanf("%d", &x);
            if( x == 1 ){
                scanf("%d %d %I64d", &tmp1, &tmp2, &num );
                if( tmp1 == tmp2 ){
                    printf("%I64d\n", num);
                    continue;
                }
                sum = query( tmp1, tmp2 );
                if( sum >= INF ){
                    printf("0\n");
                }
                else{
                    printf("%I64d\n", num/sum );
                }
            }
            else{
                scanf("%d %I64d", &tmp1, &num);
                if( ed[0][tmp1] == fa[ed[1][tmp1]] ){
                    a[pos[ed[1][tmp1]]] = min(num, a[pos[ed[1][tmp1]]]);
                    modify( pos[ed[1][tmp1]], num, 1, no-1, 1);
                }
                else{
                    a[pos[ed[0][tmp1]]] = min(num, a[pos[ed[0][tmp1]]]);
                    modify( pos[ed[0][tmp1]], num, 1, no-1, 1);
                }
            }
        }
    }
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0||bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
    {segTree[i].Max=-1;

    }
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
    {
        if(segTree[i].Max == 0)printf("......\n");
        return segTree[i].Max;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<=0||holy2<0||bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {

            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);

    if(tmp<=0||bigg/tmp<holy||holy<0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao==0)
                printf(".............");

                else if(cao<0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0||bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
    {segTree[i].Max=-1;

    }
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
    {
        return segTree[i].Max;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<=0||holy2<0||bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        if(holy == 0) printf("****\n");
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    long long tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {

            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);
    if(tmp == 0) printf(".....\n");
    else if(tmp<0||bigg/tmp<holy||holy<0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao==0)
                printf(".............");

                else if(cao<0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0||bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
    {segTree[i].Max=-1;

    }
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
    {
        return segTree[i].Max;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<=0||holy2<0||bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        if(holy == 0) printf("****\n");
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {

            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);
    if(tmp == 0) printf(".....\n");
    else if(tmp<0||bigg/tmp<holy||holy<0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao==0)
                printf(".............");

                else if(cao<0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL __int64
#define eps 1e-8
#define zero(x) ((x > +eps) - (x < -eps))
#define mem(a,b) memset(a,b,sizeof(a))
#define MOD 1000000007
#define INF 1000000000000000001LL
#define MAX 400010
using namespace std;

struct EDGE
{
    int v, next;
    int id;
    LL val;
}edges[MAX];

int n, m;
int head[MAX], cnt;
LL num[MAX], val;

void addedge(int u, int v, LL val, int id)
{
    edges[cnt].v = v;
    edges[cnt].next = head[u];
    edges[cnt].val = val;
    edges[cnt].id = id;
    head[u] = cnt ++;

    edges[cnt].v = u;
    edges[cnt].next = head[v];
    edges[cnt].val = val;
    edges[cnt].id = id;
    head[v] = cnt ++;
}

int son[MAX], fa[MAX], size[MAX], dep[MAX], id[MAX];

int dfs(int u, int pre, int depth)
{
    fa[u] = pre;
    dep[u] = depth;
    size[u] = 1;
    son[u] = -1;
    for(int i = head[u]; i != -1;i = edges[i].next){
        int re = edges[i].v;
        if(re == pre) continue;
        int cnt = dfs(re, u, depth + 1);
        if(son[u] == -1 || size[son[u]] < size[re])
        {
            son[u] = re;
            id[u] = edges[i].id;
        }
        size[u] += cnt;
    }
    return size[u];
}

int top[MAX], pos[MAX], ppos[MAX], no, ppp[MAX];

void dfs1(int u, int tops, int num)
{
    top[u] = tops;
    pos[u] = no;
    ppos[num] = no;
    ppp[no] = num;
    no++;
    if(son[u] == -1)
        return;
    dfs1(son[u], tops, id[u]);
    for(int i = head[u]; i != -1; i = edges[i].next){
        int re = edges[i].v;
        if(re == fa[u] || re == son[u])
            continue;
        dfs1(re, re, edges[i].id);
    }
}

struct TREE
{
    int left, right;
    LL sum;
    int flag;
}tree[MAX<<2];

void build_tree(int id, int left, int right)
{
    tree[id].left = left;
    tree[id].right = right;
    tree[id].sum = 0;
    tree[id].flag = 0;
    if(left == right)
    {
        tree[id].sum = num[ppp[left]];
        return;
    }
    int mid = (left + right) >> 1;
    build_tree(id<<1, left, mid);
    build_tree((id<<1)|1, mid + 1, right);
    double re = 1.0 * tree[id<<1].sum * tree[(id<<1)|1].sum;
    if(re >= INF)
    {
        tree[id].flag = 1;
        tree[id].sum = INF;
    }
    else
    {
        tree[id].sum = tree[id<<1].sum * tree[(id<<1)|1].sum;
    }
}

void update(int id, int pos, LL val)
{
    if(tree[id].left == tree[id].right)
    {
        tree[id].sum = val;
        return;
    }
    int mid = (tree[id].left + tree[id].right) >> 1;
    if(pos <= mid)
    {
        update(id<<1, pos, val);
    }
    else
    {
        update((id<<1)|1, pos,val);
    }
    double re = 1.0 * tree[id<<1].sum * tree[(id<<1)|1].sum;
    if(re >= INF)
    {
        tree[id].flag = 1;
        tree[id].sum = INF;
    }
    else
    {
        tree[id].flag = 0;
        tree[id].sum = tree[id<<1].sum * tree[(id<<1)|1].sum;
    }
}

void query(int id, int left, int right)
{
    if(tree[id].left == left && tree[id].right == right)
    {
        if(tree[id].flag)
        {
            val = 0;
            return;
        }
        val /= tree[id].sum;
        return;
    }
    int mid = (tree[id].left + tree[id].right) >> 1;
    if(right <= mid)
    {
        query(id<<1, left, right);
    }
    else if(left > mid)
    {
        query((id<<1)|1, left, right);
    }
    else
    {
        query(id<<1, left, mid);
        if(val == 0)
        {
            return;
        }
        query((id<<1)|1, mid + 1,right);
    }
}

void finds(int x, int y)
{
    int f1 = top[x] ,f2 = top[y];
    while(f1 != f2){
        if(dep[f1] < dep[f2]){
            swap(f1, f2);
            swap(x, y);
        }
        query(1, pos[f1], pos[x]);
        if(val == 0) return;
        x = fa[f1];
        f1 = top[x];
    }
    //对边权更新
    if(x == y)
        return;
    if(dep[x] < dep[y])
        swap(x,y);
    query(1,pos[son[y]],pos[x]);
}

int main()
{
    int a, b, ind;
    LL x;
    while(~scanf("%d%d",&n,&m))
    {


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0||bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
    {segTree[i].Max=-1;

    }
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
    {
        if(segTree[i].Max == 0)printf("......\n");
        return segTree[i].Max;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<=0||holy2<0||bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {

            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);
    if(tmp == 0) printf(".....\n");
    else if(tmp<0||bigg/tmp<holy||holy<0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao==0)
                printf(".............");

                else if(cao<0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0||bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
    {segTree[i].Max=-1;

    }
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
        return segTree[i].Max;
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<=0||holy2<0||bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {

            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);

    if(tmp<0||bigg/tmp<holy||holy<0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao==0)
                printf(".............");

                else if(cao<0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL __int64
#define eps 1e-8
#define zero(x) ((x > +eps) - (x < -eps))
#define mem(a,b) memset(a,b,sizeof(a))
#define MOD 1000000007
#define INF 1000000000000000001LL
#define MAX 200010
using namespace std;

struct EDGE
{
    int v, next;
    int id;
    LL val;
}edges[MAX];

int n, m;
int head[MAX], cnt;
LL num[MAX], val;

void addedge(int u, int v, LL val, int id)
{
    edges[cnt].v = v;
    edges[cnt].next = head[u];
    edges[cnt].val = val;
    edges[cnt].id = id;
    head[u] = cnt ++;

    edges[cnt].v = u;
    edges[cnt].next = head[v];
    edges[cnt].val = val;
    edges[cnt].id = id;
    head[v] = cnt ++;
}

int son[MAX], fa[MAX], size[MAX], dep[MAX], id[MAX];

int dfs(int u, int pre, int depth)
{
    fa[u] = pre;
    dep[u] = depth;
    size[u] = 1;
    son[u] = -1;
    for(int i = head[u]; i != -1;i = edges[i].next){
        int re = edges[i].v;
        if(re == pre) continue;
        int cnt = dfs(re, u, depth + 1);
        if(son[u] == -1 || size[son[u]] < size[re])
        {
            son[u] = re;
            id[u] = edges[i].id;
        }
        size[u] += cnt;
    }
    return size[u];
}

int top[MAX], pos[MAX], ppos[MAX], no, ppp[MAX];

void dfs1(int u, int tops, int num)
{
    top[u] = tops;
    pos[u] = no;
    ppos[num] = no;
    ppp[no] = num;
    no++;
    if(son[u] == -1)
        return;
    dfs1(son[u], tops, id[u]);
    for(int i = head[u]; i != -1; i = edges[i].next){
        int re = edges[i].v;
        if(re == fa[u] || re == son[u])
            continue;
        dfs1(re, re, edges[i].id);
    }
}

struct TREE
{
    int left, right;
    LL sum;
    int flag;
}tree[MAX<<2];

void build_tree(int id, int left, int right)
{
    tree[id].left = left;
    tree[id].right = right;
    tree[id].sum = 0;
    tree[id].flag = 0;
    if(left == right)
    {
        tree[id].sum = num[ppp[left]];
        return;
    }
    int mid = (left + right) >> 1;
    build_tree(id<<1, left, mid);
    build_tree((id<<1)|1, mid + 1, right);
    double re = 1.0 * tree[id<<1].sum * tree[(id<<1)|1].sum;
    if(re >= INF)
    {
        tree[id].flag = 1;
        tree[id].sum = INF;
    }
    else
    {
        tree[id].sum = tree[id<<1].sum * tree[(id<<1)|1].sum;
    }
}

void update(int id, int pos, LL val)
{
    if(tree[id].left == tree[id].right)
    {
        tree[id].sum = val;
        return;
    }
    int mid = (tree[id].left + tree[id].right) >> 1;
    if(pos <= mid)
    {
        update(id<<1, pos, val);
    }
    else
    {
        update((id<<1)|1, pos,val);
    }
    double re = 1.0 * tree[id<<1].sum * tree[(id<<1)|1].sum;
    if(re >= INF)
    {
        tree[id].flag = 1;
        tree[id].sum = INF;
    }
    else
    {
        tree[id].flag = 0;
        tree[id].sum = tree[id<<1].sum * tree[(id<<1)|1].sum;
    }
}

void query(int id, int left, int right)
{
    if(tree[id].left == left && tree[id].right == right)
    {
        if(tree[id].flag)
        {
            val = 0;
            return;
        }
        val /= tree[id].sum;
        return;
    }
    int mid = (tree[id].left + tree[id].right) >> 1;
    if(right <= mid)
    {
        query(id<<1, left, right);
    }
    else if(left > mid)
    {
        query((id<<1)|1, left, right);
    }
    else
    {
        query(id<<1, left, mid);
        if(val == 0)
        {
            return;
        }
        query((id<<1)|1, mid + 1,right);
    }
}

void finds(int x, int y)
{
    int f1 = top[x] ,f2 = top[y];
    while(f1 != f2){
        if(dep[f1] < dep[f2]){
            swap(f1, f2);
            swap(x, y);
        }
        query(1, pos[f1], pos[x]);
        if(val == 0) return;
        x = fa[f1];
        f1 = top[x];
    }
    //对边权更新
    if(x == y)
        return;
    if(dep[x] < dep[y])
        swap(x,y);
    query(1,pos[son[y]],pos[x]);
}

int main()
{
    int a, b, ind;
    LL x;
    while(~scanf("%d%d",&n,&m))
    {
        cnt = 0;
        mem(head,-1);
        for(int i = 1; i < n; i ++)
        {
            scanf("%d%d%I64d",&a,&b,&x);
            num[i] = x;
            addedge(a,b,x,i);
        }
        no = 0;
        dfs(1,0,1);
        dfs1(1,1,0);
        build_tree(1,0, no - 1);
        while(m --)
        {
            scanf("%d",&ind);
            if(ind == 1)
            {
                scanf("%d%d%I64d",&a,&b,&x);
                val = x;
                finds(a,b);
                printf("%I64d\n",val);
            }
            else
            {
                scanf("%d%I64d",&a,&x);
                update(1, ppos[a], x);
            }
        }
    }
    return 0;
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*3];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0)
        segTree[i].Max=-1;
    else if(segTree[i<<1].Max == 0)
        printf(".....\n");
    else if(bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
        segTree[i].Max=-1;
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
        return segTree[i].Max;
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<0||holy2<0)
        holy=-1;
        else if(holy1 == 0)
        printf("....\n");
        else if(bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(tmp == 0)
        printf("....\n");
        else if(holy<0||bigg/tmp<holy)//////////////
        {
            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);

    if(tmp<=0||bigg/tmp<holy||holy<=0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao<=0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long fuck;
long long bigg=1100000000000000000;
const int MAXN = 500010;
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 pos;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    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);
    }
}

//线段树
struct Node
{
    int l,r;
    long long Max;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].Max = 1;
    if(l == r)return;
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
    if((segTree[i<<1].Max<0)||segTree[(i<<1)|1].Max<0||bigg/segTree[i<<1].Max<segTree[(i<<1)|1].Max)
    {segTree[i].Max=-1;

    }
    else
    segTree[i].Max = segTree[i<<1].Max*segTree[(i<<1)|1].Max;

}/////////////////////////////////
void update(int i,int k,long long val) // 更新线段树的第k个值为val
{
    if(segTree[i].l == k && segTree[i].r == k)
    {
        segTree[i].Max = val;
        return;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid)update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}////////////////////ok
long long query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
{
    long long holy,holy1,holy2;
    if(segTree[i].l == l && segTree[i].r == r)
        return segTree[i].Max;
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid)return query(i<<1,l,r);
    else if(l > mid)return query((i<<1)|1,l,r);
    else

    {
        holy1=query(i<<1,l,mid);
        holy2=query((i<<1)|1,mid+1,r);

        if(holy1<=0||holy2<0||bigg/holy1<holy2)
        holy=-1;
        else holy=holy1*holy2;
        return holy;
    //  return -1;
    //  else
     //return query(i<<1,l,mid)*query((i<<1)|1,mid+1,r);
    }
}
long long find(int u,int v)//查询u->v边的最大值
{
    long long holy;
    int f1 = top[u], f2 = top[v];
    int tmp = 1;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        holy=query(1,p[f1],p[u]);
        if(holy<0||bigg/tmp<holy)//////////////
        {

            tmp=-1;
            //return -1;
        }
        else
        tmp = tmp*holy;

        u = fa[f1]; f1 = top[u];
}
    if(u == v)return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    holy=query(1,p[son[u]],p[v]);

    if(tmp<=0||bigg/tmp<holy||holy<0)
    return -1;
    return tmp*holy;

}
long long e[MAXN][3];
int main()
{
    int wtff;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int opp;
    int n;
  long long cao;
        init();
        scanf("%d%d",&n,&wtff);
        for(int i = 0;i < n-1;i++)
        {
            scanf("%I64d%I64d%I64d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i = 0;i < n-1; i++)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(wtff--)
        {
            scanf("%d",&opp);
            if(opp==1)
            {
                scanf("%d%d%I64d",&u,&v,&fuck);//fuck是被除的数
                if(u==v)
                printf("%I64d\n",fuck);
                else
                {

                cao=find(u,v);
                if(cao==0)
                printf(".............");

                else if(cao<0)
                printf("0\n");
                else printf("%I64d\n",fuck/cao);
                }/////////////////////
            }
            else{
                scanf("%d%I64d",&u,&fuck);
                update(1,p[e[u-1][1]],fuck);
            }
        }
      //  while(scanf("%s",op) == 1)
      //  {
      //      if(op[0] == 'D')break;
      //      scanf("%d%d",&u,&v);
       //     if(op[0] == 'Q')
       //         printf("%d\n",find(u,v));
       //     else update(1,p[e[u-1][1]],v);
      //  }

    return 0;
}


#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL __int64
#define eps 1e-8
#define zero(x) ((x > +eps) - (x < -eps))
#define mem(a,b) memset(a,b,sizeof(a))
#define MOD 1000000007
#define INF 1000000000000000001LL
#define MAX 400010
using namespace std;

struct EDGE
{
    int v, next;
    int id;
    LL val;
}edges[MAX];

int n, m;
int head[MAX], cnt;
LL num[MAX], val;

void addedge(int u, int v, LL val, int id)
{
    edges[cnt].v = v;
    edges[cnt].next = head[u];
    edges[cnt].val = val;
    edges[cnt].id = id;
    head[u] = cnt ++;

    edges[cnt].v = u;
    edges[cnt].next = head[v];
    edges[cnt].val = val;
    edges[cnt].id = id;
    head[v] = cnt ++;
}

int son[MAX], fa[MAX], size[MAX], dep[MAX], id[MAX];

int dfs(int u, int pre, int depth)
{
    fa[u] = pre;
    dep[u] = depth;
    size[u] = 1;
    son[u] = -1;
    for(int i = head[u]; i != -1;i = edges[i].next){
        int re = edges[i].v;
        if(re == pre) continue;
        int cnt = dfs(re, u, depth + 1);
        if(son[u] == -1 || size[son[u]] < size[re])
        {
            son[u] = re;
            id[u] = edges[i].id;
        }
        size[u] += cnt;
    }
    return size[u];
}

int top[MAX], pos[MAX], ppos[MAX], no, ppp[MAX];

void dfs1(int u, int tops, int num)
{
    top[u] = tops;
    pos[u] = no;
    ppos[num] = no;
    ppp[no] = num;
    no++;
    if(son[u] == -1)
        return;
    dfs1(son[u], tops, id[u]);
    for(int i = head[u]; i != -1; i = edges[i].next){
        int re = edges[i].v;
        if(re == fa[u] || re == son[u])
            continue;
        dfs1(re, re, edges[i].id);
    }
}

struct TREE
{
    int left, right;
    LL sum;
    int flag;
}tree[MAX<<2];

void build_tree(int id, int left, int right)
{
    tree[id].left = left;
    tree[id].right = right;
    tree[id].sum = 0;
    tree[id].flag = 0;
    if(left == right)
    {
        tree[id].sum = num[ppp[left]];
        return;
    }
    int mid = (left + right) >> 1;
    build_tree(id<<1, left, mid);
    build_tree((id<<1)|1, mid + 1, right);
    double re = 1.0 * tree[id<<1].sum * tree[(id<<1)|1].sum;
    if(re >= INF)
    {
        tree[id].flag = 1;
        tree[id].sum = INF;
    }
    else
    {
        tree[id].sum = tree[id<<1].sum * tree[(id<<1)|1].sum;
    }
}

void update(int id, int pos, LL val)
{
    if(tree[id].left == tree[id].right)
    {
        tree[id].sum = val;
        return;
    }
    int mid = (tree[id].left + tree[id].right) >> 1;
    if(pos <= mid)
    {
        update(id<<1, pos, val);
    }
    else
    {
        update((id<<1)|1, pos,val);
    }
    double re = 1.0 * tree[id<<1].sum * tree[(id<<1)|1].sum;
    if(re >= INF)
    {
        tree[id].flag = 1;
        tree[id].sum = INF;
    }
    else
    {
        tree[id].flag = 0;
        tree[id].sum = tree[id<<1].sum * tree[(id<<1)|1].sum;
    }
}

void query(int id, int left, int right)
{
    if(tree[id].left == left && tree[id].right == right)
    {
        if(tree[id].flag)
        {
            val = 0;
            return;
        }
        val /= tree[id].sum;
        return;
    }
    int mid = (tree[id].left + tree[id].right) >> 1;
    if(right <= mid)
    {
        query(id<<1, left, right);
    }
    else if(left > mid)
    {
        query((id<<1)|1, left, right);
    }
    else
    {
        query(id<<1, left, mid);
        if(val == 0)
        {
            return;
        }
        query((id<<1)|1, mid + 1,right);
    }
}

void finds(int x, int y)
{
    int f1 = top[x] ,f2 = top[y];
    while(f1 != f2){
        if(dep[f1] < dep[f2]){
            swap(f1, f2);
            swap(x, y);
        }
        query(1, pos[f1], pos[x]);
        if(val == 0) return;
        x = fa[f1];
        f1 = top[x];
    }
    //对边权更新
    if(x == y)
        return;
    if(dep[x] < dep[y])
        swap(x,y);
    query(1,pos[son[y]],pos[x]);
}

int main()
{
    int a, b, ind;
    LL x;
    while(~scanf("%d%d",&n,&m))
    {
     cnt = 0;
        mem(head,-1);
        for(int i = 1; i < n; i ++)
        {
            scanf("%d%d%I64d",&a,&b,&x);
            num[i] = x;
            addedge(a,b,x,i);
        }
        no = 0;
        dfs(1,0,1);
        dfs1(1,1,0);
        build_tree(1,0, no - 1);
        while(m --)
        {
            scanf("%d",&ind);
            if(ind == 1)
            {
                scanf("%d%d%I64d",&a,&b,&x);
                val = x;
                finds(a,b);
                printf("%I64d\n",val);
            }
            else
            {
                scanf("%d%I64d",&a,&x);
                update(1, ppos[a], x);
            }
        }
    }
    return 0;
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int up600;
	int up200;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

inline void dfs1(int v, int p) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;

	cur.push_back(v);
	int id = max(0, SZ(cur) - 450);
	g[v].up450 = cur[id];
	id = max(0, SZ(cur) - 200);
	g[v].up200 = cur[id];
	id = max(0, SZ(cur) - 600);
	g[v].up600 = cur[id];
	g[v].fast_link = v;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v);

	cur.pop_back();

	tout[v] = t++;
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

inline int lca200(int a, int b) {
	while (!is_upper(g[a].up200, b))
		a = g[a].up200;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;

}
inline int lca450(int a, int b) {
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;

}
inline int lca600(int a, int b) {
	while (!is_upper(g[a].up600, b))
		a = g[a].up600;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;

}

inline int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	int r = rand()%3;
	if (r == 0)
		return lca200(a, b);
	if (r == 1)
		return lca450(a, b);
	return lca600(a, b);
}

inline int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

inline void go1(int a, int c, llint &w) {
	while (w > 0 && is_upper(c, a)) {
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

inline void go2(int b, int c, llint &w);

inline void go450(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go2(g[b].up450, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

inline void go200(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go2(g[b].up200, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up200, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

inline void go600(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go2(g[b].up600, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up600, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

inline void go2(int b, int c, llint &w) {
	int r = rand()%3;
	if (r == 0)
		go200(b, c, w);
	if (r == 1)
		go450(b, c, w);
	if (r == 2)
		go600(b, c, w);
}

inline void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

inline void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

map<pii, llint> ans;

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			if (ans.count(pii{a, b})) {
				printf("%I64d\n", ans[pii{a, b}]);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
			ans.clear();
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

void dfs1(int v, int p) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;

	cur.push_back(v);
	int id = max(0, SZ(cur) - 350);
	g[v].up450 = cur[id];
	g[v].fast_link = v;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v);

	cur.pop_back();

	tout[v] = t++;
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;
}

int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

void go1(int a, int c, llint &w) {
	while (w > 0 && is_upper(c, a)) {
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

void go2(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go2(g[b].up450, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

map<pii, llint> ans;

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			if (ans.count(pii{a, b})) {
				printf("%I64d\n", ans[pii{a, b}]);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
			ans.clear();
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int up600;
	int up200;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

inline void dfs1(int v, int p) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;

	cur.push_back(v);
	int id = max(0, SZ(cur) - 450);
	g[v].up450 = cur[id];
	id = max(0, SZ(cur) - 200);
	g[v].up200 = cur[id];
	id = max(0, SZ(cur) - 600);
	g[v].up600 = cur[id];
	g[v].fast_link = v;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v);

	cur.pop_back();

	tout[v] = t++;
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

inline int lca200(int a, int b) {
	while (!is_upper(g[a].up200, b))
		a = g[a].up200;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;

}
inline int lca450(int a, int b) {
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;

}
inline int lca600(int a, int b) {
	while (!is_upper(g[a].up600, b))
		a = g[a].up600;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;

}

inline int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	int r = rand()%3;
	if (r == 0)
		return lca200(a, b);
	if (r == 1)
		return lca450(a, b);
	return lca600(a, b);
}

inline int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

inline void go1(int a, int c, llint &w) {
	while (w > 0 && is_upper(c, a)) {
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

inline void go450(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go450(g[b].up450, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

inline void go200(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go200(g[b].up200, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up200, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

inline void go600(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go600(g[b].up600, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up600, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

inline void go2(int b, int c, llint &w) {
	int r = rand()%3;
	if (r == 0)
		go200(b, c, w);
	if (r == 1)
		go450(b, c, w);
	if (r == 2)
		go600(b, c, w);
}

inline void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

inline void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

map<pii, llint> ans;

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			if (ans.count(pii{a, b})) {
				printf("%I64d\n", ans[pii{a, b}]);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
			ans.clear();
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];

inline void dfs1(int v, int p) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;

	g[v].fast_link = v;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v);

	tout[v] = t++;
}

inline bool is_upper(int a, int b) {
	return tin[a] <= tin[b]  && tin[b] <= tout[a] &&
				 tin[a] <= tout[b] && tout[b] <= tout[a];
}

inline int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

inline void go1(int a, int b, llint &w) {
	while (w > 0 && !is_upper(a, b)) {
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

inline void go2(int a, int b, llint &w) {
	vl v;
	while (v.size()<65 && !is_upper(b, a)) {
		if (g[b].w != 1) {
			v.push_back(g[b].w);
			b = g[b].p;
		} else {
			b = find(b);
		}
	}
	for (int i = SZ(v)-1; i >= 0; --i)
		w /= v[i];
}

inline void solve(int a, int b, llint &w) {
	if (w == 0)
		return;
	go1(a, b, w);
	go2(a, b, w);
}

inline void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1);

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			solve(a, b, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

void dfs1(int v, int p) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;

	cur.push_back(v);
	int id = max(0, SZ(cur) - 450);
	g[v].up450 = cur[id];
	g[v].fast_link = v;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v);

	cur.pop_back();

	tout[v] = t++;
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;
}

int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

void go1(int a, int c, llint &w) {
	while (w > 0 && is_upper(c, a)) {
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

void go2(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go2(g[b].up450, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int depth[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

void dfs1(int v, int p, int d) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;
	depth[v] = d;
	cur.push_back(v);
	int id = max(0, SZ(cur) - 450);
	g[v].up450 = id;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v, d + 1);

	cur.pop_back();

	tout[v] = t++;
}

void dfs2(int v, int p) {

	if (p != -1) {
		if (g[v].w == 1) {
			g[v].fast_link = g[p].fast_link;
		} else {
			g[v].fast_link = v;
		}
	} else {
		g[v].fast_link = 0;
	}
	for (Rib r: g[v].next) if (r.to != p)
		dfs2(r.to, v);
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;
}

int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

void go1(int a, int c, llint &w) {
	while (w > 0) {
		if (!is_upper(c, a))
			return;
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

void go2(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 1; --i) {
		w /= v[i];
	}
}

void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1, 0);
	dfs2(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int fast_link;
	int p;
	llint w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

void dfs1(int v, int p) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;

	cur.push_back(v);
	int id = max(0, SZ(cur) - 550);
	g[v].up450 = cur[id];
	g[v].fast_link = v;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v);

	cur.pop_back();

	tout[v] = t++;
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;
}

int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

void go1(int a, int c, llint &w) {
	while (w > 0 && is_upper(c, a)) {
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

void go2(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	go2(g[b].up450, c, w);
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 0; --i) {
		w /= v[i];
	}
}

void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

map<pii, llint> ans;

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			if (ans.count(pii{a, b})) {
				printf("%I64d\n", ans[pii{a, b}]);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
			ans.clear();
		}
	}
}


// Smile please :)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <iomanip>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <climits>
//#include <unordered_map>
//#include <unordered_set>
using namespace std;

//#undef KVARK_DEBUG

#ifdef KVARK_DEBUG
	#include "../h/debug.h"
#else
#define dbg(...) (void(1));
#define dbg2(...) (void(1));
#define dbg3(...) (void(1));
#define dbg4(...) (void(1));
#define dbg5(...) (void(1));
#define dbgp(...) (void(1));
#define dbg_arr(...) (void(1));
#define dbg_vec(...) (void(1));
#endif

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<double, int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<vector<int> > vvi;
typedef vector<vector<pii> > vvpii;
typedef vector<vector<long long> > vvl;
typedef vector<long long> vl;
typedef long long int llint;

#define ALL(v) (v.begin()), (v.end())
#define SZ(v) ((int)((v).size()))
#define endl "\n"

void task();

int main(){
#ifdef KVARK
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	srand(time(0));
#endif
//	ios_base::sync_with_stdio(0);

	task();

#ifdef KVARK_DEBUG
	my_debug::printProcessInfo();
#endif
	return 0;
}
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
const int M = 2e5+10;

struct Rib {
	int to;
	llint w;
};

struct V {
	vector<Rib> next;
	int up450;
	int fast_link;
	int p;
	int w;
};

int n, q;
V g[N];
int tin[N];
int tout[N];
int depth[N];
int t;
map<pii, int> ribs_id;
map<pii, llint> ribs_w;
int id_to_v[N];
vi cur;

void dfs1(int v, int p, int d) {
	if (p != -1) {
		id_to_v[ribs_id[pii{p, v}]] = v;
		g[v].p = p;
		g[v].w = ribs_w[pii{p, v}];
	}
	tin[v] = t++;
	depth[v] = d;
	cur.push_back(v);
	int id = max(0, SZ(cur) - 450);
	g[v].up450 = id;

	for (Rib r: g[v].next) if (r.to != p)
		dfs1(r.to, v, d + 1);

	cur.pop_back();

	tout[v] = t++;
}

void dfs2(int v, int p) {

	if (p != -1) {
		if (g[v].w == 1) {
			g[v].fast_link = g[p].fast_link;
		} else {
			g[v].fast_link = v;
		}
	} else {
		g[v].fast_link = 0;
	}
	for (Rib r: g[v].next) if (r.to != p)
		dfs2(r.to, v);
}

inline bool is_upper(int a, int b) {
	return tin[a] < tin[b]  && tin[b] < tout[a] &&
				 tin[a] < tout[b] && tout[b] < tout[a];
}

int lca(int a, int b) {
	if (is_upper(a, b)) return a;
	if (is_upper(b, a)) return b;
	while (!is_upper(g[a].up450, b))
		a = g[a].up450;
	while (g[a].p != -1 && !is_upper(g[a].p, b))
		a = g[a].p;
	return g[a].p;
}

int find(int v) {
	if (v == 0)
		return 0;
	if (g[v].w > 1)
		return v;
	return g[v].fast_link = find(g[v].fast_link == v ? g[v].p : g[v].fast_link);
}

void go1(int a, int c, llint &w) {
	while (w > 0) {
		if (!is_upper(c, a))
			return;
		if (g[a].w != 1) {
			w /= g[a].w;
			a = g[a].p;
		} else {
			a = find(a);
		}
	}
}

void go2(int b, int c, llint &w) {
	if (!is_upper(c, b))
		return;
	if (w == 0)
		return;
	vi v;
	{
		int a = b;
		while (is_upper(g[b].up450, a)) {
			if (g[a].w != 1) {
				v.push_back(g[a].w);
				a = g[a].p;
			} else {
				a = find(a);
			}
		}
	}
	for (int i = SZ(v) - 1; i >= 0 && w > 1; --i) {
		w /= v[i];
	}
}

void solve(int a, int b, int c, llint &w) {
	if (w == 0)
		return;
	go1(a, c, w);
	go2(b, c, w);
}

void change(int id, llint c) {
	int v = id_to_v[id];
	g[v].w = c;
}

void task() {
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		llint w;
		scanf("%d %d %I64d", &a, &b, &w);
		--a, --b;
		ribs_id[pii{a,b}] = i;
		ribs_id[pii{b,a}] = i;
		ribs_w[pii{a, b}] = w;
		ribs_w[pii{b, a}] = w;
		g[a].next.push_back(Rib{b, w});
		g[b].next.push_back(Rib{a, w});
	}
	dfs1(0, -1, 0);
	dfs2(0, -1);

//	dbg(is_upper())

	while (q--) {
		int cmd;
		scanf("%d", &cmd);
		if (cmd == 1) {
			int a, b;
			llint w;
			scanf("%d %d %I64d", &a, &b, &w);
			--a, --b;
			if (a == b) {
				printf("%I64d\n", w);
				continue;
			}
			int c = lca(a, b);
			solve(a, b, c, w);
			printf("%I64d\n", w);
		} else if (cmd == 2) {
			int p;
			llint c;
			scanf("%d %I64d", &p, &c);
			--p;
			change(p, c);
		}
	}
}