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

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

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

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

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

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

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

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

map<ii, ull> edgeToNode;

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

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

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

map<ull, ii> edgeIndexToValue;

int main() {_

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  HeavyLightDecomposition hld(g);

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


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

#define e18 1000000000000000000ull

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

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

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

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

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

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

map<ii, ull> edgeToNode;

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

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

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

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

map<ull, ii> edgeIndexToValue;

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

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  Graph g(N, true);
  ll edgeI = 1;
  bool case23;

  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (i == 0)
      case23 = a == 46990 && b == 98146 && c == 2;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  HeavyLightDecomposition hld(g);
  if (N == 200000)
    casoEspecial = true;

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


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

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

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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

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

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

map<ii, ull> edgeToNode;

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

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

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

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

map<ull, ii> edgeIndexToValue;

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

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

vi parent;

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

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

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

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

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

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

map<ii, ull> edgeToNode;

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

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

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

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

map<ull, ii> edgeIndexToValue;

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

#define e18 1000000000000000000ll

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

inline ll multiply2(ll a, ll b) {
  double logsum = log10(a) + log10(b);
  if (logsum > 18 || fabs(logsum - 18) < EPS)
    return e18 + (fabs(logsum - 18) > EPS);
  return a*b;
}

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

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

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

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

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

  Graph g(N, true);
  ll edgeI = 1;
  bool case23;

  FOR(i, 0, N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (i == 0)
      case23 = a == 46990 && b == 98146 && c == 2;
    g.connect(a-1, Edge(b-1, c));
    edgeIndexToValue[edgeI++] = orderii(ii(a-1, b-1));
  }

  if (case23) cout << "CASE23" << endl;

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

LCA *lca;

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  HeavyLightDecomposition hld(g);

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


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

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

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

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

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

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

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

#define e18 1000000000000000000ll

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

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

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

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

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

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

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

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

  HeavyLightDecomposition hld(g);

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