#include <bits/stdc++.h>
using namespace std;
const long long mod1 = 2147483647;
const long long mod2 = 1224736769;
const long long mod3 = 2000000011;
const long long modpow(long long a, long long b, long long mod) {
  long long res = 1;
  while (b) {
    if (b & 1) res = res * a % mod;
    a = a * a % mod;
    b /= 2;
  }
  return res;
}
const long long modinv(long long a, long long mod) {
  return modpow(a, mod - 2, mod);
}
long long garner(long long a, long long b, long long mod1, long long mod2) {
  long long x = (b - a) * modinv(mod1, mod2);
  x %= mod2;
  x += mod2;
  x %= mod2;
  return a + x * mod1;
}
struct lint {
  long long x, y, z;
  double w;
  lint() : x(1), y(1), z(1), w(0) {}
  lint(long long a) : x(a % mod1), y(a % mod2), z(a % mod3), w(log(a)) {}
  lint operator*(lint b) {
    lint res;
    res.x = x * b.x % mod1;
    res.y = y * b.y % mod2;
    res.z = z * b.z % mod3;
    res.w = w + b.w;
    return res;
  }
  lint operator/(lint b) {
    lint res;
    res.x = x * modinv(b.x, mod1) % mod1;
    res.y = y * modinv(b.y, mod2) % mod2;
    res.z = z * modinv(b.z, mod3) % mod3;
    res.w = w - b.w;
    return res;
  }
  lint &operator*=(const lint &b) {
    x = x * b.x % mod1;
    y = y * b.y % mod2;
    z = z * b.z % mod3;
    w += b.w;
    return *this;
  }
  lint &operator/=(const lint &b) {
    x = x * modinv(b.x, mod1) % mod1;
    y = y * modinv(b.y, mod2) % mod2;
    z = z * modinv(b.z, mod3) % mod3;
    w = w - b.w;
    return *this;
  }
  operator long long() {
    const double X = 18 * log(10) + log(2.0);
    if (w >= X) return 2e18;
    long long a = garner(x, y, mod1, mod2);
    long long b = garner(y, z, mod2, mod3);
    if (a == 0 && b == 0) return 0;
    if (a != 0) return a;
    if (b != 0) return b;
  }
};
struct LCA {
  vector<vector<int>> G, parent;
  vector<int> depth;
  LCA(int n) : G(n), parent(24, vector<int>(n)), depth(n) {}
  void add(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }
  void build(int root = 0) {
    dfs(root, -1);
    for (int i = (0); i < (23); i++)
      for (int j = (0); j < (G.size()); j++) {
        if (parent[i][j] == -1)
          parent[i + 1][j] = -1;
        else
          parent[i + 1][j] = parent[i][parent[i][j]];
      }
  }
  void dfs(int curr, int prev) {
    parent[0][curr] = prev;
    for (int next : G[curr])
      if (next != prev) {
        depth[next] = depth[curr] + 1;
        dfs(next, curr);
      }
  }
  int query(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    for (int i = (24) - 1; i >= (0); i--)
      if (depth[u] - depth[v] >= 1 << i) {
        u = parent[i][u];
      }
    if (u == v) return u;
    for (int i = (24) - 1; i >= (0); i--)
      if (parent[i][u] != parent[i][v]) {
        u = parent[i][u];
        v = parent[i][v];
      }
    return parent[0][u];
  }
};
struct HL {
  vector<vector<int>> G, path;
  vector<int> parent, head, order, heads, heavy, depth;
  int root;
  HL(int n)
      : G(n), heavy(n, -1), parent(n), head(n), order(n), path(n), depth(n) {}
  void add(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }
  int dfs(int curr, int prev = -1) {
    int res = 1;
    head[curr] = curr;
    parent[curr] = prev;
    int maxv = -1;
    for (int next : G[curr])
      if (next != prev) {
        int d = dfs(next, curr);
        res += d;
        if (maxv < d) maxv = d, heavy[curr] = next;
      }
    return res;
  }
  void dfs2(int curr, int prev = -1) {
    if (head[curr] == curr) heads.push_back(curr);
    path[head[curr]].push_back(curr);
    for (int next : G[curr])
      if (next != prev) {
        if (next == heavy[curr]) {
          head[next] = head[curr];
          order[next] = order[curr] + 1;
        }
        depth[next] = depth[curr] + (next != heavy[curr]);
        dfs2(next, curr);
      }
  }
  void build(int root = 0) {
    this->root = root;
    dfs(root);
    dfs2(root);
  }
  struct Iterator {
    int u, v;
    HL *hl;
    Iterator(HL *hl, int u, int v) : hl(hl), u(u), v(v) {}
    tuple<int, int, int> next() {
      if (hl->depth[u] == hl->depth[v]) {
        if (hl->head[u] == hl->head[v]) {
          auto m = minmax(hl->order[u], hl->order[v]);
          u = -1;
          return make_tuple(hl->head[v], m.first, m.second + 1);
        }
      }
      if (hl->depth[u] < hl->depth[v]) swap(u, v);
      int pu = u;
      u = hl->parent[hl->head[u]];
      return make_tuple(hl->head[pu], 0, hl->order[pu] + 1);
    }
    bool has_next() { return u != -1; }
  };
  Iterator iterator(int u, int v) { return Iterator(this, u, v); }
};
struct SegmentTree {
  vector<lint> prod;
  int size;
  void init(int n) {
    size = 1;
    while (size < n) size *= 2;
    prod.resize(size * 2);
  }
  void set(int k, long long v) {
    k += size - 1;
    prod[k] = lint(v);
  }
  void build() {
    for (int k = (size - 1) - 1; k >= (0); k--) {
      prod[k] = prod[k * 2 + 1] * prod[k * 2 + 2];
    }
  }
  lint get(int k) {
    k += size - 1;
    return prod[k];
  }
  void update(int k, long long v) {
    k += size - 1;
    prod[k] = lint(v);
    while (k) {
      k = (k - 1) / 2;
      prod[k] = prod[k * 2 + 1] * prod[k * 2 + 2];
    }
  }
  lint query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l) return lint();
    if (a <= l && r <= b) return prod[k];
    lint x = query(a, b, k * 2 + 1, l, (l + r) / 2);
    lint y = query(a, b, k * 2 + 2, (l + r) / 2, r);
    return x * y;
  }
  lint query(int a, int b) { return query(a, b, 0, 0, size); }
};
struct HLSolver {
  HL hl;
  vector<SegmentTree> tr;
  HLSolver(int n) : hl(n), tr(n) {}
  void add(int u, int v) { hl.add(u, v); }
  void build() {
    hl.build();
    for (int h : hl.heads) {
      tr[h].init(hl.path[h].size());
    }
  }
  void set(int u, long long x) { tr[hl.head[u]].set(hl.order[u], x); }
  void build_segment_tree() {
    for (int h : hl.heads) {
      tr[h].build();
    }
  }
  void update(int u, long long x) { tr[hl.head[u]].update(hl.order[u], x); }
  lint get(int u) { return tr[hl.head[u]].get(hl.order[u]); }
  long long query(int u, int v, int l) {
    lint res;
    res /= get(l);
    auto it = hl.iterator(u, v);
    while (it.has_next()) {
      int h, l, r;
      tie(h, l, r) = it.next();
      res *= tr[h].query(l, r);
    }
    return (long long)res;
  }
};
int depth[202020];
vector<int> G[202020];
void dfs(int curr, int prev = -1) {
  for (int next : G[curr])
    if (next != prev) {
      depth[next] = depth[curr] + 1;
      dfs(next, curr);
    }
}
int main() {
  int n, m;
  cin >> n >> m;
  vector<pair<int, int>> es(n - 1);
  vector<long long> val(n - 1);
  HLSolver hl(n);
  LCA lca(n);
  for (int i = (0); i < (n - 1); i++) {
    int u, v;
    long long x;
    scanf("%d %d %I64d", &u, &v, &x);
    u--;
    v--;
    G[u].push_back(v);
    G[v].push_back(u);
    es[i] = make_pair(u, v);
    hl.add(u, v);
    val[i] = x;
    lca.add(u, v);
  }
  hl.build();
  lca.build();
  dfs(0);
  for (int i = (0); i < (n - 1); i++) {
    int u, v;
    tie(u, v) = es[i];
    if (depth[u] > depth[v]) swap(es[i].first, es[i].second);
  }
  for (int i = (0); i < (n - 1); i++) {
    int u, v;
    tie(u, v) = es[i];
    hl.set(v, val[i]);
  }
  hl.build_segment_tree();
  for (int i_ = (0); i_ < (m); i_++) {
    int qid;
    scanf("%d", &qid);
    if (qid == 1) {
      int a, b;
      long long y;
      scanf("%d %d %I64d", &a, &b, &y);
      a--;
      b--;
      int l = lca.query(a, b);
      long long ans = hl.query(a, b, l);
      ans = y / ans;
      printf("%I64d\n", ans);
    } else {
      int p;
      long long c;
      scanf("%d %I64d", &p, &c);
      int u, v;
      tie(u, v) = es[p - 1];
      hl.update(v, c);
    }
  }
  return 0;
}
