#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
typedef vector <vector <int>> VVI;
typedef pair <LL, LL> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

#define int LL

int mul(int x, int y)
{
    LL ans = (LL)x * y;
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T> class SegmentTree
{
    int maxn = 1000000;
    vector <T> t;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build (a, v * 2 + 1, tl, tm);
            build (a, v * 2 + 2, tm + 1, tr);
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T sum(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return 1;
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return mul(sum(v * 2 + 1, tl, tm, l, min(r, tm)),
sum(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = new_val;
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update (v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update (v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree (int n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    int size() { return maxn; }
    SegmentTree () {}
    SegmentTree (const vector <T> &a) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T sum(int l, int r)
    {
        return sum(0, 0, maxn - 1, l, r);
    }
};

class HeavyLightDecomp
{
    vector <SegmentTree <int>> tr;
    vector <int> next;
    vector <vector <int>> up;
    int timer = 0;
    int tr_size = 0;
    vector <int> used;
    vector <int> tin;
    vector <int> tout;
    vector <int> par;
    vector <int> s;
    vector <PII> pos;
    const vector <vector <int>> &g;
    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
public:
    int upper(int a, int b)
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }
    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }
private:
    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }
    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }
    void go_up(int x, int p)
    {
        //cout << "UP " << tr_size - 1 << ": " << x << " " << p << endl;
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree <int> (vector <int> (p + 1, 1));
        }
    }
    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }
public:
    HeavyLightDecomp(const vector <vector <int>> &tree): g(tree)
    {
        init();
    }
    void update(int x, int val)
    {
        tr[pos[x].first].update(pos[x].second, val);
    }
    LL sum(int x, int y)
    {
        int p = lca(x, y);
        LL ans = 1;
        if (pos[x].first == pos[p].first) {
            ans = mul(ans, tr[pos[x].first].sum(pos[x].second, pos[p].second));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second));
        }
        if (pos[y].first == pos[p].first) {
            ans = mul(ans, tr[pos[y].first].sum(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }
};

vector <vector <PII>> g;
vector <int> used;
vector <int> p;

void dfs(int x, int t)
{
    p[x] = t;
    used[x] = 1;
    for (auto i: g[x]) {
        if (used[i.first]) {
            continue;
        }
        dfs(i.first, i.second);
    }
}

signed main()
{
    int n, m;
    scanf("%I64d%I64d", &n, &m);
    g.resize(n);
    used.resize(n);
    p.resize(n);
    vector <vector <int>> g2(n);
    vector <PII> edge(n);
    FOR (i, 0, n - 1) {
        int a, b, c;
        scanf("%I64%I64%I64d", &a, &b, &c);
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        g2[a].push_back(b);
        g2[b].push_back(a);
        edge[i] = {a, b};
    }
    dfs(0, 1);
    HeavyLightDecomp h(g2);
    FOR (i, 0, n) {
        h.update(i, p[i]);
    }
    FOR (i, 0, m) {
        int t;
        scanf("%I64d", &t);
        if (t == 1) {
            int a, b, y;
            scanf("%I64d%I64%I64", &a, &b, &y);
            --a;
            --b;
            int l = h.lca(a, b);
            int x = h.sum(l, l);
            h.update(l, 1);
            int ans = h.sum(a, b);
            h.update(l, x);
            printf("%I64d", y / ans);
        } else {
            int p, c;
            scanf("%I64d%I64d", p, c);
            --p;
            int x = edge[p].first;
            int y = edge[p].second;
            if (h.upper(x, y)) {
                h.update(y, c);
            } else {
                h.update(x, c);
            }
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
typedef pair <int, int> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

int MAXN = 3000000;

template <class T>
class BaseUpdater
{
  public:
    virtual T current_update(T current, T value) const { return std::numeric_limits<T>::min();}
};

template <class T>
class AddUpdater: public BaseUpdater<T>
{
  public:
    T current_update(T current, T value) const override {
        return current + value;
    }
};

template <class T>
class AssignUpdater: public BaseUpdater<T>
{
  public:
    T current_update(T current, T value) const override {
        return value;
    }
};

template <class T>
class BaseCombiner
{
  public:
    virtual T combine(T left, T right) const { return std::numeric_limits<T>::min();}
    virtual T default_value() const { return std::numeric_limits<T>::min();}
};

template <class T>
class SumCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return left + right;
    }
    T default_value() const override {
        return 0;
    }
};

template <class T>
class MaxCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return max(left, right);
    }
    T default_value() const override {
        return std::numeric_limits<T>::min();
    }
};

template <class T>
class MinCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return min(left, right);
    }
    T default_value() const override {
        return std::numeric_limits<T>::max();
    }
};

LL mul(LL x, LL y)
{
    if ((LD)x * (LD)y > 4e18) {
        return 2e18;
    }
    LL ans = (LL)x * y;
    return ans;
}

template <class T>
class MulCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return mul(left, right);
    }
    T default_value() const override {
        return 1;
    }
};

LL trunc_log(LL x)
{
    if (x == 0) {
        return -1;
    }
    return 63 - __builtin_clzll(x);
}

template <class T, class Combiner, class Updater> class SegmentTreeDown
{
    Combiner combiner;
    Updater updater;
    int n;
    int maxn = 1000000;
    int start_pos;
    vector<T> t;
    void build(const vector<T> &a) {
        copy(a.begin(), a.end(), t.begin() + start_pos);
        for (int i = maxn - 1; i > 0; --i) {
            t[i] = combiner.combine(t[i << 1], t[i << 1 | 1]);
        }
    }

    T query_impl(int l, int r) {
         T res = combiner.default_value();
         if (l > r) {
            return res;
         }
         ++r;
         for (l += start_pos, r += start_pos; l < r; l >>= 1, r >>= 1) {
             if (l & 1) {
                 res = combiner.combine(res, t[l++]);
             }
             if (r & 1) {
                 res = combiner.combine(res, t[--r]);
             }
         }
         return res;
    }

    void update_impl(int pos, T value) {
        pos += start_pos;
        t[pos] = updater.current_update(t[pos], value);
        for (; pos > 1; pos >>= 1) {
            t[pos >> 1] = combiner.combine(t[pos], t[pos ^ 1]);
        }
    }
public:
    SegmentTreeDown(){}
    SegmentTreeDown(int n)
       : n(n),
         maxn((1 << (trunc_log(n - 1) + 1))),
         start_pos(maxn),
         t(2 * maxn, combiner.default_value())
    {
    }
    SegmentTreeDown(const vector<T> &a): n(a.size()), maxn((1 << (trunc_log(n - 1) + 1))), start_pos(maxn)
    { // copy-paste!
        t.resize(2 * maxn, combiner.default_value());
        build(a);
    }
    void update(int pos, T value)
    {
        update_impl(pos, value);
    }
    T query(int l, int r)
    {
        return query_impl(l, r);
    }
    int size() const
    {
        return n;
    }
};

template <class T, class Combiner, class Updater> class SegmentTree
{
    Combiner combiner;
    Updater updater;
    int maxn = 1000000;
    vector <T> t;
    int n;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build(a, v * 2 + 1, tl, tm);
            build(a, v * 2 + 2, tm + 1, tr);
            t[v] = combiner.combine(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T query(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return combiner.default_value();
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return combiner.combine(query(v * 2 + 1, tl, tm, l, min(r, tm)),
                                query(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = updater.current_update(t[v], new_val);
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update(v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update(v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = combiner.combine(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree(){}
    SegmentTree(int n): n(n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    SegmentTree (const vector <T> &a): n(a.size()) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T query(int l, int r)
    {
        return query(0, 0, maxn - 1, l, r);
    }
    int size() const
    {
        return n;
    }
};

class Lca
{
  public:
    Lca(const vector<vector<int>> &g)
    {
        timer = 0;
        par.resize(g.size());
        d.assign(g.size(), -1);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(g, 0);
    }

    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }

    int dist(int a, int b)
    {
        int p = lca(a, b);
        return d[a] + d[b] - 2 * d[p];
    }

    int upper(int a, int b) // is a upper than b in tree
    {
        return tin[a] <= tin[b] && tout[a] >= tout[b];
    }

    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }

    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }

  private:
    vector<int> d;
    vector<int> tin;
    vector<int> tout;
    vector<int> par;
    vector<int> s;
    vector<vector<int>> up;
    int timer = 0;

    void dfs(const vector<vector<int>> &g, int t, int p = 0, int depth = 0)
    {
        s[t] = 1;
        d[t] = depth;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (d[i] != -1) {
                continue;
            }
            dfs(g, i, t, depth + 1);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
};

template<template<typename, typename, typename> class SegmentTree, class Combiner, class Updater, class Label>
class HeavyLightDecomp
{
  public:

    HeavyLightDecomp(const vector<vector<int>> &tree, const vector<Label> &labels): g(tree) // From tree and labels
    {
        labeled_edges = false;
        init(labels);
    }

    HeavyLightDecomp(const vector<vector<int>> &tree, bool labeled_edges): labeled_edges(labeled_edges), g(tree), lca(g) // From tree and labels
    {
        init_hld();
    }

    HeavyLightDecomp(const vector<vector<pair<int, Label>>> &tree): g(remove_labels(tree)), lca(g) // From tree labels on edges
    {
        const Label UNDEFINED_VALUE = 0;
        labeled_edges = true;
        vector<Label> labels(tree.size());
        vector<int> used(tree.size());
        fill_labels(0, UNDEFINED_VALUE, tree, labels, used);
        init(labels);
    }

    void update_vertex(int vertex, Label val)
    {
        assert(!labeled_edges);
        update(vertex, val);
    }

    void update_edge(PII edge, Label val)
    {
        assert(labeled_edges);
        if (lca.upper(edge.first, edge.second)) {
            update(edge.second, val);
        } else {
            update(edge.first, val);
        }
    }
    Label query(int x, int y)
    {
        int p = lca.lca(x, y);
        Label ans = combiner.default_value();
        if (pos[x].first == pos[p].first) {
            ans = combiner.combine(ans, tr[pos[x].first].query(pos[x].second, pos[p].second - (labeled_edges ? 1 : 0)));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, int(tr[pos[t].first].size()) - 1));
                t = next[pos[t].first];
            }
            ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, pos[p].second - (labeled_edges ? 1 : 0)));
        }
        if (pos[y].first == pos[p].first) { // copy-paste !!
            ans = combiner.combine(ans, tr[pos[y].first].query(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, int(tr[pos[t].first].size()) - 1));
                t = next[pos[t].first];
            }
            ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }

    PII get_pos(int v)
    {
        return pos[v];
    }
  private:
    Combiner combiner;
    Updater updater;
    bool labeled_edges = false;
    vector<SegmentTree<Label, Combiner, Updater>> tr;
    vector<int> next;
    vector<vector<int>> g; // не нужно его хранить после init
    Lca lca;
    int tr_size = 0;
    vector<PII> pos;

    void init_hld()
    {
        tr.assign(g.size(), {});
        next.assign(g.size(), {});
        for (int i = 0; i < g.size(); ++i) {
            int flag = 1;
            for (auto j: g[i]) {
                if (lca.upper(j, i)) {
                    continue;
                }
                if (lca.heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            next[i] = -1;
            go_up(i, 0, i + 1);
        }
    }

    void go_up(int x, int p, int tr_size)
    {
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (lca.upper(x, i)) {
                continue;
            }
            if (lca.heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1, tr_size);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree<Label, Combiner, Updater>(p + 1);
        }
    }

    void init(const vector<Label> &labels)
    {
        pos.resize(g.size());
        init_hld();
        for (int i = 0; i < labels.size(); ++i) { // O(n) ?
            update(i, labels[i]);
        }
    }

    void update(int vertex, Label val)
    {
        tr[pos[vertex].first].update(pos[vertex].second, val);
    }

    void fill_labels(int x, Label label, const vector<vector<pair<int, Label>>> &g, vector<Label> &labels, vector<int> &used)
    {
        labels[x] = label;
        used[x] = 1;
        for (auto v: g[x]) {
            if (used[v.first]) {
                continue;
            }
            fill_labels(v.first, v.second, g, labels, used);
        }
    }

    vector<vector<int>> remove_labels(const vector<vector<pair<int, Label>>> &labeled_tree) {
        vector<vector<int>> tree(labeled_tree.size());
        for (int i = 0; i < tree.size(); ++i) {
            tree[i].reserve(labeled_tree[i].size());
            for (const auto &vertex: labeled_tree[i]) {
                tree[i].push_back(vertex.first);
            }
        }
        return tree;
    }
};

int main()
{
    int n, m;
    cin >> n >> m;
    vector<PII> edges;
    vector<vector<pair<int, LL>>> g(n);
    FOR (i, 0, n - 1) {
        LL a, b, c;
        cin >> a >> b >> c;
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        edges.push_back({a, b});
    }
    HeavyLightDecomp<SegmentTreeDown, MulCombiner<LL>, AssignUpdater<LL>, LL> h(g);
    FOR (i, 0, m) {
        LL t;
        cin >> t;
        if (t == 1) {
            LL a, b, y;
            cin >> a >> b >> y;
            --a;
            --b;
            LL ans = h.query(a, b);
            cout << y / ans << endl;
        } else {
            LL p, c;
            cin >> p >> c;
            --p;
            int x = edges[p].first;
            int y = edges[p].second;
            h.update_edge({x, y}, c);
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
typedef vector <vector <int>> VVI;
typedef pair <LL, LL> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

#define int LL

int mul(int x, int y)
{
    LL ans = (LL)x * y;
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T> class SegmentTree
{
    int maxn = 1000000;
    vector <T> t;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build (a, v * 2 + 1, tl, tm);
            build (a, v * 2 + 2, tm + 1, tr);
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T sum(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return 1;
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return mul(sum(v * 2 + 1, tl, tm, l, min(r, tm)),
sum(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = new_val;
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update (v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update (v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree (int n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    int size() { return maxn; }
    SegmentTree () {}
    SegmentTree (const vector <T> &a) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T sum(int l, int r)
    {
        return sum(0, 0, maxn - 1, l, r);
    }
};

class HeavyLightDecomp
{
    vector <SegmentTree <int>> tr;
    vector <int> next;
    vector <vector <int>> up;
    int timer = 0;
    int tr_size = 0;
    vector <int> used;
    vector <int> tin;
    vector <int> tout;
    vector <int> par;
    vector <int> s;
    vector <PII> pos;
    const vector <vector <int>> &g;
    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
public:
    int upper(int a, int b)
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }
    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }
private:
    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }
    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }
    void go_up(int x, int p)
    {
        //cout << "UP " << tr_size - 1 << ": " << x << " " << p << endl;
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree <int> (vector <int> (p + 1, 1));
        }
    }
    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }
public:
    HeavyLightDecomp(const vector <vector <int>> &tree): g(tree)
    {
        init();
    }
    void update(int x, int val)
    {
        tr[pos[x].first].update(pos[x].second, val);
    }
    LL sum(int x, int y)
    {
        int p = lca(x, y);
        LL ans = 1;
        if (pos[x].first == pos[p].first) {
            ans = mul(ans, tr[pos[x].first].sum(pos[x].second, pos[p].second));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second));
        }
        if (pos[y].first == pos[p].first) {
            ans = mul(ans, tr[pos[y].first].sum(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }
};

vector <vector <PII>> g;
vector <int> used;
vector <int> p;

void dfs(int x, int t)
{
    p[x] = t;
    used[x] = 1;
    for (auto i: g[x]) {
        if (used[i.first]) {
            continue;
        }
        dfs(i.first, i.second);
    }
}

signed main()
{
    int n, m;
    scanf("%I64d%I64d", &n, &m);
    g.resize(n);
    used.resize(n);
    p.resize(n);
    vector <vector <int>> g2(n);
    vector <PII> edge(n);
    FOR (i, 0, n - 1) {
        int a, b, c;
        scanf("%I64d%I64d%I64d", &a, &b, &c);
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        g2[a].push_back(b);
        g2[b].push_back(a);
        edge[i] = {a, b};
    }
    dfs(0, 1);
    HeavyLightDecomp h(g2);
    FOR (i, 0, n) {
        h.update(i, p[i]);
    }
    FOR (i, 0, m) {
        int t;
        scanf("%I64d", &t);
        if (t == 1) {
            int a, b, y;
            scanf("%I64d%I64d%I64d", &a, &b, &y);
            --a;
            --b;
            int l = h.lca(a, b);
            int x = h.sum(l, l);
            h.update(l, 1);
            int ans = h.sum(a, b);
            h.update(l, x);
            printf("%I64d\n", y / ans);
        } else {
            int p, c;
            scanf("%I64d%I64d", &p, &c);
            --p;
            int x = edge[p].first;
            int y = edge[p].second;
            if (h.upper(x, y)) {
                h.update(y, c);
            } else {
                h.update(x, c);
            }
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
typedef pair <int, int> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

int MAXN = 3000000;

template <class T>
class BaseUpdater
{
  public:
    virtual T current_update(T current, T value) const { return std::numeric_limits<T>::min();}
};

template <class T>
class AddUpdater: public BaseUpdater<T>
{
  public:
    T current_update(T current, T value) const override {
        return current + value;
    }
};

template <class T>
class AssignUpdater: public BaseUpdater<T>
{
  public:
    T current_update(T current, T value) const override {
        return value;
    }
};

template <class T>
class BaseCombiner
{
  public:
    virtual T combine(T left, T right) const { return std::numeric_limits<T>::min();}
    virtual T default_value() const { return std::numeric_limits<T>::min();}
};

template <class T>
class SumCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return left + right;
    }
    T default_value() const override {
        return 0;
    }
};

template <class T>
class MaxCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return max(left, right);
    }
    T default_value() const override {
        return std::numeric_limits<T>::min();
    }
};

template <class T>
class MinCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return min(left, right);
    }
    T default_value() const override {
        return std::numeric_limits<T>::max();
    }
};

LL mul(LL x, LL y)
{
    LL ans = (LL)x * y;
    if (ans == 0) {
        return ans;
    }
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T>
class MulCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return mul(left, right);
    }
    T default_value() const override {
        return 1;
    }
};

LL trunc_log(LL x)
{
    return 63 - __builtin_clzll(x);
}

template <class T, class Combiner, class Updater> class SegmentTreeDown
{
    int maxn = 1000000;
    vector<T> t;
    Combiner combiner;
    Updater updater;
    int start_pos;
    int n;
    void build(const vector<T> &a) {
        copy(a.begin(), a.end(), t.begin() + start_pos);
        for (int i = maxn - 1; i > 0; --i) {
            t[i] = combiner.combine(t[i << 1], t[i << 1 | 1]);
        }
    }

    T query_impl(int l, int r) {
         ++r;
         T res = combiner.default_value();
         for (l += start_pos, r += start_pos; l < r; l >>= 1, r >>= 1) {
             if (l & 1) {
                 res = combiner.combine(res, t[l++]);
             }
             if (r & 1) {
                 res = combiner.combine(res, t[--r]);
             }
         }
         return res;
    }

    void update_impl(int pos, T value) {
        pos += start_pos;
        t[pos] = updater.current_update(t[pos], value);
        for (; pos > 1; pos >>= 1) {
            t[pos >> 1] = combiner.combine(t[pos], t[pos ^ 1]);
        }
    }
public:
    SegmentTreeDown(){}
    SegmentTreeDown(int n): n(n)
    {
        maxn = (1 << (trunc_log(n - 1) + 1));
        start_pos = maxn;
        t.resize(2 * maxn, combiner.default_value());
    }
    SegmentTreeDown(const vector<T> &a): n(a.size()) { // copy-paste!
        maxn = (1 << (trunc_log(n - 1) + 1));
        start_pos = maxn;
        t.resize(2 * maxn, combiner.default_value());
        build(a);
    }
    void update(int pos, T value)
    {
        update_impl(pos, value);
    }
    T query(int l, int r)
    {
        return query_impl(l, r);
    }
    int size() const
    {
        return n;
    }
};

template<template<typename, typename, typename> class SegmentTree, class Combiner, class Updater, class Label>
class HeavyLightDecomp
{
  public:
    HeavyLightDecomp(const vector<vector<int>> &tree, const vector<Label> &labels): g(tree) // From tree and labels
    {
        labeled_edges = false;
        init(labels);
    }

    HeavyLightDecomp(const vector<vector<int>> &tree, bool labeled_edges): g(tree), labeled_edges(labeled_edges) // From tree and labels
    {
        init();
    }

    HeavyLightDecomp(const vector<vector<pair<int, Label>>> &tree): g(remove_labels(tree)) // From tree labels on edges
    {
        const Label UNDEFINED_VALUE = 0;
        labeled_edges = true;
        vector<Label> labels(tree.size());
        vector<int> used(tree.size());
        fill_labels(0, UNDEFINED_VALUE, tree, labels, used);
        init(labels);
    }

    void update_vertex(int vertex, Label val)
    {
        assert(!labeled_edges);
        update(vertex, val);
    }

    void update_edge(PII edge, Label val)
    {
        assert(labeled_edges);
        if (upper(edge.first, edge.second)) {
            update(edge.second, val);
        } else {
            update(edge.first, val);
        }
    }
    Label query(int x, int y)
    {
        int p = lca(x, y);
        Label ans = combiner.default_value();
        if (pos[x].first == pos[p].first) {
            ans = combiner.combine(ans, tr[pos[x].first].query(pos[x].second, pos[p].second - (labeled_edges ? 1 : 0)));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, int(tr[pos[t].first].size()) - 1));
                t = next[pos[t].first];
            }
            ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, pos[p].second - (labeled_edges ? 1 : 0)));
        }
        if (pos[y].first == pos[p].first) { // copy-paste !!
            ans = combiner.combine(ans, tr[pos[y].first].query(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, int(tr[pos[t].first].size()) - 1));
                t = next[pos[t].first];
            }
            ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }

    PII get_pos(int v)
    {
        return pos[v];
    }
  private:
    Combiner combiner;
    Updater updater;
    bool labeled_edges = false;
    vector<SegmentTree<Label, Combiner, Updater>> tr;
    vector<int> next;
    vector<vector<int>> up;
    int timer = 0;
    int tr_size = 0;
    vector<int> used;
    vector<int> tin;
    vector<int> tout;
    vector<int> par;
    vector<int> s;
    vector<PII> pos;
    const vector<vector<int>> &g;

    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }

    int upper(int a, int b) // в lca
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }

    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }

    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }

    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }

    void go_up(int x, int p)
    {
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree<Label, Combiner, Updater>(p + 1);
        }
    }

    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }

    void init(const vector<Label> &labels)
    {
        init();
        for (int i = 0; i < labels.size(); ++i) { // O(n) ?
            update(i, labels[i]);
        }
    }

    void update(int vertex, Label val)
    {
        tr[pos[vertex].first].update(pos[vertex].second, val);
    }

    void fill_labels(int x, Label label, const vector<vector<pair<int, Label>>> &g, vector<Label> &labels, vector<int> &used)
    {
        labels[x] = label;
        used[x] = 1;
        for (auto v: g[x]) {
            if (used[v.first]) {
                continue;
            }
            fill_labels(v.first, v.second, g, labels, used);
        }
    }

    vector<vector<int>> remove_labels(const vector<vector<pair<int, Label>>> &labeled_tree) {
        vector<vector<int>> tree(labeled_tree.size());
        for (int i = 0; i < tree.size(); ++i) {
            tree[i].reserve(labeled_tree[i].size());
            for (const auto &vertex: labeled_tree[i]) {
                tree[i].push_back(vertex.first);
            }
        }
        return tree;
    }
};

int main()
{
    int n, m;
    cin >> n >> m;
    vector<PII> edges;
    vector<vector<pair<int, LL>>> g(n);
    FOR (i, 0, n - 1) {
        LL a, b, c;
        cin >> a >> b >> c;
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        edges.push_back({a, b});
    }
    HeavyLightDecomp<SegmentTreeDown, MulCombiner<LL>, AssignUpdater<LL>, LL> h(g);
    FOR (i, 0, m) {
        LL t;
        cin >> t;
        if (t == 1) {
            LL a, b, y;
            cin >> a >> b >> y;
            --a;
            --b;
            LL ans = h.query(a, b);
            cout << y / ans << endl;
        } else {
            LL p, c;
            cin >> p >> c;
            --p;
            int x = edges[p].first;
            int y = edges[p].second;
            h.update_edge({x, y}, c);
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
typedef vector <vector <int>> VVI;
typedef pair <LL, LL> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

#define int LL

int mul(int x, int y)
{
    LL ans = (LL)x * y;
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T> class SegmentTree
{
    int maxn = 1000000;
    vector <T> t;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build (a, v * 2 + 1, tl, tm);
            build (a, v * 2 + 2, tm + 1, tr);
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T sum(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return 1;
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return mul(sum(v * 2 + 1, tl, tm, l, min(r, tm)),
sum(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = new_val;
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update (v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update (v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree (int n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    int size() { return maxn; }
    SegmentTree () {}
    SegmentTree (const vector <T> &a) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T sum(int l, int r)
    {
        return sum(0, 0, maxn - 1, l, r);
    }
};

class HeavyLightDecomp
{
    vector <SegmentTree <int>> tr;
    vector <int> next;
    vector <vector <int>> up;
    int timer = 0;
    int tr_size = 0;
    vector <int> used;
    vector <int> tin;
    vector <int> tout;
    vector <int> par;
    vector <int> s;
    vector <PII> pos;
    const vector <vector <int>> &g;
    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
public:
    int upper(int a, int b)
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }
    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }
private:
    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }
    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }
    void go_up(int x, int p)
    {
        //cout << "UP " << tr_size - 1 << ": " << x << " " << p << endl;
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree <int> (vector <int> (p + 1, 1));
        }
    }
    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }
public:
    HeavyLightDecomp(const vector <vector <int>> &tree): g(tree)
    {
        init();
    }
    void update(int x, int val)
    {
        tr[pos[x].first].update(pos[x].second, val);
    }
    LL sum(int x, int y)
    {
        int p = lca(x, y);
        LL ans = 1;
        if (pos[x].first == pos[p].first) {
            ans = mul(ans, tr[pos[x].first].sum(pos[x].second, pos[p].second));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second));
        }
        if (pos[y].first == pos[p].first) {
            ans = mul(ans, tr[pos[y].first].sum(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }
};

vector <vector <PII>> g;
vector <int> used;
vector <int> p;

void dfs(int x, int t)
{
    p[x] = t;
    used[x] = 1;
    for (auto i: g[x]) {
        if (used[i.first]) {
            continue;
        }
        dfs(i.first, i.second);
    }
}

signed main()
{
    int n, m;
    scanf("%I64d%I64d", &n, &m);
    g.resize(n);
    used.resize(n);
    p.resize(n);
    vector <vector <int>> g2(n);
    vector <PII> edge(n);
    FOR (i, 0, n - 1) {
        int a, b, c;
        scanf("%I64d%I64d%I64d", &a, &b, &c);
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        g2[a].push_back(b);
        g2[b].push_back(a);
        edge[i] = {a, b};
    }
    dfs(0, 1);
    HeavyLightDecomp h(g2);
    FOR (i, 0, n) {
        h.update(i, p[i]);
    }
    FOR (i, 0, m) {
        int t;
        scanf("%I64d", &t);
        if (t == 1) {
            int a, b, y;
            scanf("%I64d%I64%I64", &a, &b, &y);
            --a;
            --b;
            int l = h.lca(a, b);
            int x = h.sum(l, l);
            h.update(l, 1);
            int ans = h.sum(a, b);
            h.update(l, x);
            printf("%I64d\n", y / ans);
        } else {
            int p, c;
            scanf("%I64d%I64d", &p, &c);
            --p;
            int x = edge[p].first;
            int y = edge[p].second;
            if (h.upper(x, y)) {
                h.update(y, c);
            } else {
                h.update(x, c);
            }
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
typedef pair <int, int> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

int MAXN = 3000000;

template <class T>
class BaseUpdater
{
  public:
    virtual T current_update(T current, T value) const { return std::numeric_limits<T>::min();}
};

template <class T>
class AddUpdater: public BaseUpdater<T>
{
  public:
    T current_update(T current, T value) const override {
        return current + value;
    }
};

template <class T>
class AssignUpdater: public BaseUpdater<T>
{
  public:
    T current_update(T current, T value) const override {
        return value;
    }
};

template <class T>
class BaseCombiner
{
  public:
    virtual T combine(T left, T right) const { return std::numeric_limits<T>::min();}
    virtual T default_value() const { return std::numeric_limits<T>::min();}
};

template <class T>
class SumCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return left + right;
    }
    T default_value() const override {
        return 0;
    }
};

template <class T>
class MaxCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return max(left, right);
    }
    T default_value() const override {
        return std::numeric_limits<T>::min();
    }
};

template <class T>
class MinCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return min(left, right);
    }
    T default_value() const override {
        return std::numeric_limits<T>::max();
    }
};

LL mul(LL x, LL y)
{
    LL ans = (LL)x * y;
    if (ans == 0) {
        return ans;
    }
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T>
class MulCombiner: public BaseCombiner<T>
{
  public:
    T combine(T left, T right) const override {
        return mul(left, right);
    }
    T default_value() const override {
        return 1;
    }
};

LL trunc_log(LL x)
{
    return 63 - __builtin_clzll(x);
}

template <class T, class Combiner, class Updater> class SegmentTreeDown
{
    int maxn = 1000000;
    vector<T> t;
    Combiner combiner;
    Updater updater;
    int start_pos;
    int n;
    void build(const vector<T> &a) {
        copy(a.begin(), a.end(), t.begin() + start_pos);
        for (int i = maxn - 1; i > 0; --i) {
            t[i] = combiner.combine(t[i << 1], t[i << 1 | 1]);
        }
    }

    T query_impl(int l, int r) {
         ++r;
         T res = combiner.default_value();
         for (l += start_pos, r += start_pos; l < r; l >>= 1, r >>= 1) {
             if (l & 1) {
                 res = combiner.combine(res, t[l++]);
             }
             if (r & 1) {
                 res = combiner.combine(res, t[--r]);
             }
         }
         return res;
    }

    void update_impl(int pos, T value) {
        pos += start_pos;
        t[pos] = updater.current_update(t[pos], value);
        for (; pos > 1; pos >>= 1) {
            t[pos >> 1] = combiner.combine(t[pos], t[pos ^ 1]);
        }
    }
public:
    SegmentTreeDown(){}
    SegmentTreeDown(int n): n(n)
    {
        maxn = (1 << (trunc_log(n - 1) + 1));
        start_pos = maxn;
        t.resize(2 * maxn, combiner.default_value());
    }
    SegmentTreeDown(const vector<T> &a): n(a.size()) { // copy-paste!
        maxn = (1 << (trunc_log(n - 1) + 1));
        start_pos = maxn;
        t.resize(2 * maxn, combiner.default_value());
        build(a);
    }
    void update(int pos, T value)
    {
        update_impl(pos, value);
    }
    T query(int l, int r)
    {
        return query_impl(l, r);
    }
    int size() const
    {
        return n;
    }
};

template<template<typename, typename, typename> class SegmentTree, class Combiner, class Updater, class Label>
class HeavyLightDecomp
{
  public:
    HeavyLightDecomp(const vector<vector<int>> &tree, const vector<Label> &labels): g(tree) // From tree and labels
    {
        labeled_edges = false;
        init(labels);
    }

    HeavyLightDecomp(const vector<vector<int>> &tree, bool labeled_edges): g(tree), labeled_edges(labeled_edges) // From tree and labels
    {
        init();
    }

    HeavyLightDecomp(const vector<vector<pair<int, Label>>> &tree): g(remove_labels(tree)) // From tree labels on edges
    {
        const Label UNDEFINED_VALUE = 0;
        labeled_edges = true;
        vector<Label> labels(tree.size());
        vector<int> used(tree.size());
        fill_labels(0, UNDEFINED_VALUE, tree, labels, used);
        init(labels);
    }

    void update_vertex(int vertex, Label val)
    {
        assert(!labeled_edges);
        update(vertex, val);
    }

    void update_edge(PII edge, Label val)
    {
        assert(labeled_edges);
        if (upper(edge.first, edge.second)) {
            update(edge.second, val);
        } else {
            update(edge.first, val);
        }
    }
    Label query(int x, int y)
    {
        int p = lca(x, y);
        Label ans = combiner.default_value();
        if (pos[x].first == pos[p].first) {
            ans = combiner.combine(ans, tr[pos[x].first].query(pos[x].second, pos[p].second - (labeled_edges ? 1 : 0)));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, int(tr[pos[t].first].size()) - 1));
                t = next[pos[t].first];
            }
            ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, pos[p].second - (labeled_edges ? 1 : 0)));
        }
        if (pos[y].first == pos[p].first) { // copy-paste !!
            ans = combiner.combine(ans, tr[pos[y].first].query(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, int(tr[pos[t].first].size()) - 1));
                t = next[pos[t].first];
            }
            ans = combiner.combine(ans, tr[pos[t].first].query(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }

    PII get_pos(int v)
    {
        return pos[v];
    }
  private:
    Combiner combiner;
    Updater updater;
    bool labeled_edges = false;
    vector<SegmentTree<Label, Combiner, Updater>> tr;
    vector<int> next;
    vector<vector<int>> up;
    int timer = 0;
    int tr_size = 0;
    vector<int> used;
    vector<int> tin;
    vector<int> tout;
    vector<int> par;
    vector<int> s;
    vector<PII> pos;
    const vector<vector<int>> &g;

    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }

    int upper(int a, int b) // в lca
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }

    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }

    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }

    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }

    void go_up(int x, int p)
    {
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree<Label, Combiner, Updater>(p + 1);
        }
    }

    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }

    void init(const vector<Label> &labels)
    {
        init();
        for (int i = 0; i < labels.size(); ++i) { // O(n) ?
            update(i, labels[i]);
        }
    }

    void update(int vertex, Label val)
    {
        tr[pos[vertex].first].update(pos[vertex].second, val);
    }

    void fill_labels(int x, Label label, const vector<vector<pair<int, Label>>> &g, vector<Label> &labels, vector<int> &used)
    {
        labels[x] = label;
        used[x] = 1;
        for (auto v: g[x]) {
            if (used[v.first]) {
                continue;
            }
            fill_labels(v.first, v.second, g, labels, used);
        }
    }

    vector<vector<int>> remove_labels(const vector<vector<pair<int, Label>>> &labeled_tree) {
        vector<vector<int>> tree(labeled_tree.size());
        for (int i = 0; i < tree.size(); ++i) {
            tree[i].reserve(labeled_tree[i].size());
            for (const auto &vertex: labeled_tree[i]) {
                tree[i].push_back(vertex.first);
            }
        }
        return tree;
    }
};

int main()
{
    int n = 200000, m = 0;
    //cin >> n >> m;
    vector<PII> edges;
    vector<vector<pair<int, LL>>> g(n);
    FOR (i, 0, n - 1) {
        LL a = i + 1, b = i + 2, c = 1e13;
        //cin >> a >> b >> c;
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        edges.push_back({a, b});
    }
    HeavyLightDecomp<SegmentTreeDown, MulCombiner<LL>, AssignUpdater<LL>, LL> h(g);
    FOR (i, 0, m) {
        LL t;
        cin >> t;
        if (t == 1) {
            LL a, b, y;
            cin >> a >> b >> y;
            --a;
            --b;
            LL ans = h.query(a, b);
            cout << y / ans << endl;
        } else {
            LL p, c;
            cin >> p >> c;
            --p;
            int x = edges[p].first;
            int y = edges[p].second;
            h.update_edge({x, y}, c);
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
typedef vector <vector <int>> VVI;
typedef pair <LL, LL> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

#define int LL

int mul(int x, int y)
{
    LL ans = (LL)x * y;
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T> class SegmentTree
{
    int maxn = 1000000;
    vector <T> t;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build (a, v * 2 + 1, tl, tm);
            build (a, v * 2 + 2, tm + 1, tr);
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T sum(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return 1;
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return mul(sum(v * 2 + 1, tl, tm, l, min(r, tm)),
sum(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = new_val;
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update (v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update (v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree (int n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    int size() { return maxn; }
    SegmentTree () {}
    SegmentTree (const vector <T> &a) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T sum(int l, int r)
    {
        return sum(0, 0, maxn - 1, l, r);
    }
};

class HeavyLightDecomp
{
    vector <SegmentTree <int>> tr;
    vector <int> next;
    vector <vector <int>> up;
    int timer = 0;
    int tr_size = 0;
    vector <int> used;
    vector <int> tin;
    vector <int> tout;
    vector <int> par;
    vector <int> s;
    vector <PII> pos;
    const vector <vector <int>> &g;
    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
public:
    int upper(int a, int b)
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }
    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }
private:
    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }
    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }
    void go_up(int x, int p)
    {
        //cout << "UP " << tr_size - 1 << ": " << x << " " << p << endl;
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree <int> (vector <int> (p + 1, 1));
        }
    }
    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }
public:
    HeavyLightDecomp(const vector <vector <int>> &tree): g(tree)
    {
        init();
    }
    void update(int x, int val)
    {
        tr[pos[x].first].update(pos[x].second, val);
    }
    LL sum(int x, int y)
    {
        int p = lca(x, y);
        LL ans = 1;
        if (pos[x].first == pos[p].first) {
            ans = mul(ans, tr[pos[x].first].sum(pos[x].second, pos[p].second));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second));
        }
        if (pos[y].first == pos[p].first) {
            ans = mul(ans, tr[pos[y].first].sum(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }
};

vector <vector <PII>> g;
vector <int> used;
vector <int> p;

void dfs(int x, int t)
{
    p[x] = t;
    used[x] = 1;
    for (auto i: g[x]) {
        if (used[i.first]) {
            continue;
        }
        dfs(i.first, i.second);
    }
}

signed main()
{
    int n, m;
    scanf("%I64d%I64d", &n, &m);
    g.resize(n);
    used.resize(n);
    p.resize(n);
    vector <vector <int>> g2(n);
    vector <PII> edge(n);
    FOR (i, 0, n - 1) {
        int a, b, c;
        scanf("%I64%I64%I64d", &a, &b, &c);
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        g2[a].push_back(b);
        g2[b].push_back(a);
        edge[i] = {a, b};
    }
    dfs(0, 1);
    HeavyLightDecomp h(g2);
    FOR (i, 0, n) {
        h.update(i, p[i]);
    }
    FOR (i, 0, m) {
        int t;
        scanf("%I64d", &t);
        if (t == 1) {
            int a, b, y;
            scanf("%I64d%I64%I64", &a, &b, &y);
            --a;
            --b;
            int l = h.lca(a, b);
            int x = h.sum(l, l);
            h.update(l, 1);
            int ans = h.sum(a, b);
            h.update(l, x);
            printf("%I64d\n", y / ans);
        } else {
            int p, c;
            scanf("%I64d%I64d", &p, &c);
            --p;
            int x = edge[p].first;
            int y = edge[p].second;
            if (h.upper(x, y)) {
                h.update(y, c);
            } else {
                h.update(x, c);
            }
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
typedef vector <vector <int>> VVI;
typedef pair <LL, LL> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

#define int LL

int mul(int x, int y)
{
    LL ans = (LL)x * y;
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T> class SegmentTree
{
    int maxn = 1000000;
    vector <T> t;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build (a, v * 2 + 1, tl, tm);
            build (a, v * 2 + 2, tm + 1, tr);
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T sum(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return 1;
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return mul(sum(v * 2 + 1, tl, tm, l, min(r, tm)),
sum(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = new_val;
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update (v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update (v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree (int n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    int size() { return maxn; }
    SegmentTree () {}
    SegmentTree (const vector <T> &a) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T sum(int l, int r)
    {
        return sum(0, 0, maxn - 1, l, r);
    }
};

class HeavyLightDecomp
{
    vector <SegmentTree <int>> tr;
    vector <int> next;
    vector <vector <int>> up;
    int timer = 0;
    int tr_size = 0;
    vector <int> used;
    vector <int> tin;
    vector <int> tout;
    vector <int> par;
    vector <int> s;
    vector <PII> pos;
    const vector <vector <int>> &g;
    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
public:
    int upper(int a, int b)
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }
    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }
private:
    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }
    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }
    void go_up(int x, int p)
    {
        //cout << "UP " << tr_size - 1 << ": " << x << " " << p << endl;
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree <int> (vector <int> (p + 1, 1));
        }
    }
    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }
public:
    HeavyLightDecomp(const vector <vector <int>> &tree): g(tree)
    {
        init();
    }
    void update(int x, int val)
    {
        tr[pos[x].first].update(pos[x].second, val);
    }
    LL sum(int x, int y)
    {
        int p = lca(x, y);
        LL ans = 1;
        if (pos[x].first == pos[p].first) {
            ans = mul(ans, tr[pos[x].first].sum(pos[x].second, pos[p].second));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second));
        }
        if (pos[y].first == pos[p].first) {
            ans = mul(ans, tr[pos[y].first].sum(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }
};

vector <vector <PII>> g;
vector <int> used;
vector <int> p;

void dfs(int x, int t)
{
    p[x] = t;
    used[x] = 1;
    for (auto i: g[x]) {
        if (used[i.first]) {
            continue;
        }
        dfs(i.first, i.second);
    }
}

signed main()
{
    int n, m;
    cin >> n >> m;
    g.resize(n);
    used.resize(n);
    p.resize(n);
    vector <vector <int>> g2(n);
    vector <PII> edge(n);
    FOR (i, 0, n - 1) {
        int a, b, c;
        cin >> a >> b >> c;
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        g2[a].push_back(b);
        g2[b].push_back(a);
        edge[i] = {a, b};
    }
    dfs(0, 1);
    HeavyLightDecomp h(g2);
    FOR (i, 0, n) {
        h.update(i, p[i]);
    }
    FOR (i, 0, m) {
        int t;
        cin >> t;
        if (t == 1) {
            int a, b, y;
            cin >> a >> b >> y;
            --a;
            --b;
            int l = h.lca(a, b);
            int x = h.sum(l, l);
            h.update(l, 1);
            int ans = h.sum(a, b);
            h.update(l, x);
            cout << y / ans << endl;
        } else {
            int p, c;
            cin >> p >> c;
            --p;
            int x = edge[p].first;
            int y = edge[p].second;
            if (h.upper(x, y)) {
                h.update(y, c);
            } else {
                h.update(x, c);
            }
        }
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265359
#endif // M_PI
#define endl "\n"
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
typedef vector <vector <int>> VVI;
typedef pair <int, int> PII;
const int MOD = 1000000007;
template <class T> typename T::value_type arr_sum(const T& v, int n) { typename T::value_type sum = 0; FOR(i, 0, n) sum += v[i]; return sum; }
struct Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;

#define int LL

int mul(int x, int y)
{
    LL ans = (LL)x * y;
    LL x2 = ans / y;
    if (x2 == x) {
        return ans;
    }
    return 2e18;
}

template <class T> class SegmentTree
{
    int maxn = 1000000;
    vector <T> t;
    void build(const vector <T> &a, int v, int tl, int tr) {
        if (tl == tr) {
            t[v] = a[tl];
        } else {
            int tm = (tl + tr) / 2;
            build (a, v * 2 + 1, tl, tm);
            build (a, v * 2 + 2, tm + 1, tr);
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
    T sum(int v, int tl, int tr, int l, int r) {
        if (l > r) {
            return 1;
        }
        if (l == tl && r == tr) {
            return t[v];
        }
        int tm = (tl + tr) / 2;
        return mul(sum(v * 2 + 1, tl, tm, l, min(r, tm)),
sum(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r));
    }
    void update(int v, int tl, int tr, int pos, T new_val) {
        if (tl == tr) {
            t[v] = new_val;
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                update (v * 2 + 1, tl, tm, pos, new_val);
            } else {
                update (v * 2 + 2, tm + 1, tr, pos, new_val);
            }
            t[v] = mul(t[v * 2 + 1], t[v * 2 + 2]);
        }
    }
public:
    SegmentTree (int n)
    {
        maxn = n;
        t.resize(4 * maxn);
    }
    int size() { return maxn; }
    SegmentTree () {}
    SegmentTree (const vector <T> &a) {
        maxn = a.size();
        t.resize(4 * maxn);
        build(a, 0, 0, maxn - 1);
    }
    void update(int pos, T add)
    {
        update(0, 0, maxn - 1, pos, add);
    }
    T sum(int l, int r)
    {
        return sum(0, 0, maxn - 1, l, r);
    }
};

class HeavyLightDecomp
{
    vector <SegmentTree <int>> tr;
    vector <int> next;
    vector <vector <int>> up;
    int timer = 0;
    int tr_size = 0;
    vector <int> used;
    vector <int> tin;
    vector <int> tout;
    vector <int> par;
    vector <int> s;
    vector <PII> pos;
    const vector <vector <int>> &g;
    void dfs(int t, int p = 0)
    {
        s[t] = 1;
        used[t] = 1;
        par[t] = p;
        tin[t] = ++timer;
        up[t][0] = p;
        FOR (i, 1, int(up[t].size())) {
            up[t][i] = up[up[t][i - 1]][i - 1];
        }
        for (auto i: g[t]) {
            if (used[i]) {
                continue;
            }
            dfs(i, t);
            s[t] += s[i];
        }
        tout[t] = ++timer;
    }
public:
    int upper(int a, int b)
    {
        return tout[a] >= tout[b] && tin[a] <= tin[b];
    }
    int lca(int a, int b)
    {
        if (upper(a, b)) {
            return a;
        }
        if (upper(b, a)) {
            return b;
        }
        FORR (i, up[a].size() - 1, -1) {
            if (!upper(up[a][i], b)) {
                a = up[a][i];
            }
        }
        return up[a][0];
    }
private:
    inline int light(int i, int j)
    {
        return 2 * s[j] < s[i];
    }
    inline int heavy(int i, int j)
    {
        return 2 * s[j] >= s[i];
    }
    void go_up(int x, int p)
    {
        //cout << "UP " << tr_size - 1 << ": " << x << " " << p << endl;
        pos[x] = {tr_size - 1, p};
        int flag = 0;
        for (auto i: g[x]) {
            if (upper(x, i)) {
                continue;
            }
            if (heavy(i, x)) {
                flag = 1;
                go_up(i, p + 1);
            } else {
                next[tr_size - 1] = i;
            }
        }
        if (!flag) {
            tr[tr_size - 1] = SegmentTree <int> (vector <int> (p + 1, 1));
        }
    }
    void init()
    {
        timer = 0;
        pos.resize(g.size());
        par.resize(g.size());
        used.assign(g.size(), 0);
        tin.resize(g.size());
        tout.resize(g.size());
        up.resize(g.size());
        s.resize(g.size());
        int l = 1;
        while ((1 << l) <= int(g.size())) {
            ++l;
        }
        for (auto &i: up) {
           i.resize(l + 1);
        }
        dfs(0);
        FOR (i, 0, int(g.size())) {
            int flag = 1;
            for (auto j: g[i]) {
                if (upper(j, i)) {
                    continue;
                }
                if (heavy(i, j)) {
                    flag = 0;
                    break;
                }
            }
            if (!flag) {
                continue;
            }
            ++tr_size;
            tr.resize(tr_size);
            next.resize(tr_size);
            next[tr_size - 1] = -1;
            go_up(i, 0);
        }
    }
public:
    HeavyLightDecomp(const vector <vector <int>> &tree): g(tree)
    {
        init();
    }
    void update(int x, int val)
    {
        tr[pos[x].first].update(pos[x].second, val);
    }
    LL sum(int x, int y)
    {
        int p = lca(x, y);
        LL ans = 1;
        if (pos[x].first == pos[p].first) {
            ans = mul(ans, tr[pos[x].first].sum(pos[x].second, pos[p].second));
        } else {
            int t = x;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second));
        }
        if (pos[y].first == pos[p].first) {
            ans = mul(ans, tr[pos[y].first].sum(pos[y].second, pos[p].second - 1));
        } else {
            int t = y;
            while (pos[t].first != pos[p].first) {
                ans = mul(ans, tr[pos[t].first].sum(pos[t].second, tr[pos[t].first].size() - 1));
                t = next[pos[t].first];
            }
            ans = mul(ans, tr[pos[t].first].sum(pos[t].second, pos[p].second - 1));
        }
        return ans;
    }
};

vector <vector <PII>> g;
vector <int> used;
vector <int> p;

void dfs(int x, int t)
{
    p[x] = t;
    used[x] = 1;
    for (auto i: g[x]) {
        if (used[i.first]) {
            continue;
        }
        dfs(i.first, i.second);
    }
}

signed main()
{
    int n, m;
    cin >> n >> m;
    g.resize(n);
    used.resize(n);
    p.resize(n);
    vector <vector <int>> g2(n);
    vector <PII> edge(n);
    FOR (i, 0, n - 1) {
        int a, b, c;
        cin >> a >> b >> c;
        --a;
        --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
        g2[a].push_back(b);
        g2[b].push_back(a);
        edge[i] = {a, b};
    }
    dfs(0, 1);
    HeavyLightDecomp h(g2);
    FOR (i, 0, n) {
        h.update(i, p[i]);
    }
    FOR (i, 0, m) {
        int t;
        cin >> t;
        if (t == 1) {
            int a, b, y;
            cin >> a >> b >> y;
            --a;
            --b;
            int l = h.lca(a, b);
            int x = h.sum(l, l);
            h.update(l, 1);
            int ans = h.sum(a, b);
            h.update(l, x);
            cout << y / ans << endl;
        } else {
            int p, c;
            cin >> p >> c;
            --p;
            int x = edge[p].first;
            int y = edge[p].second;
            if (h.upper(x, y)) {
                h.update(y, c);
            } else {
                h.update(x, c);
            }
        }
    }
}


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

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

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

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

int qe, n, m, no;

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

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

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

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

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

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

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

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

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