#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define FOR(i, a, n) for (int i = (a); i < (n); ++i)
#define REP(i, n) FOR(i, 0, n)
using namespace std;

class HeavyLightDecomposition {
    void dfs_sz(int v) {
        for (int& nv : g[v]) if (nv != par[v]) {
            par[nv] = v;
            dep[nv] = dep[v] + 1;
            dfs_sz(nv);
            sub[v] += sub[nv];
            if (sub[nv] > sub[g[v][0]]) swap(nv, g[v][0]);
        }
    }
    
    void dfs_hld(int v, int c, int& pos) {
        vid[v] = pos++;
        inv[vid[v]] = v;
        type[v] = c;
        for (int& nv : g[v]) if (nv != par[v]) {
            head[nv] = (nv == g[v][0] ? head[v] : nv);
            dfs_hld(nv, c, pos);
        }
    }

public:
    int n;
    vector<vector<int>> g;
    vector<int> vid, head, sub, par, dep, inv, type;

    HeavyLightDecomposition(vector<vector<int>>& g)
        : n(g.size()), g(g), vid(n, -1), head(n), sub(n, 1), par(n, -1), dep(n, 0), inv(n), type(n) {}

    void build(vector<int> rs = {0}) {
        int c = 0, pos = 0;
        for (int r : rs) {
            dfs_sz(r);
            head[r] = r;
            dfs_hld(r, c++, pos);
        }
    }

    int lca(int u, int v) {
        while (1) {
            if (vid[u] > vid[v]) swap(u, v);
            if (head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }

    int distance(int u, int v) {
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }

    template <typename F> void for_each(int u, int v, const F& f) {
        while (1) {
            if (vid[u] > vid[v]) swap(u, v);
            f(max(vid[head[v]], vid[u]), vid[v] + 1);
            if (head[u] != head[v]) v = par[head[v]];
            else break;
        }
    }

    template <typename F> void for_each_edge(int u, int v, const F& f) {
        while (1) {
            if (vid[u] > vid[v]) swap(u, v);
            if (head[u] != head[v]) {
                f(vid[head[v]], vid[v] + 1);
                v = par[head[v]];
            } else {
                if (u != v) f(vid[u] + 1, vid[v] + 1);
                break;
            }
        }
    }
};

template <class M = int, class OM = int> class LazySegmentTree {
    void init(int _n) {
        for (n = 1, lev = 0; n < _n; n <<= 1, ++lev);
        d.assign(n << 1, u1);
        lz.assign(n << 1, u0);
    }
    inline M reflect(int k, int len) {
        return lz[k] == u0 ? d[k] : g(d[k], p(lz[k], len));
    }
    inline void propagate(int k, int len) {
        if (lz[k] == u0) return;
        lz[(k << 1) | 0] = h(lz[(k << 1) | 0], lz[k]);
        lz[(k << 1) | 1] = h(lz[(k << 1) | 1], lz[k]);
        d[k] = reflect(k, len);
        lz[k] = u0;
    }
    inline void thrust(int k) {
        for (int i = lev; i > 0; --i) propagate(k >> i, n >> (lev - i));
    }
    inline void recalc(int k) {
        int len = 1;
        while (len <<= 1, k >>= 1) {
            M lhs = reflect((k << 1) | 0, len >> 1);
            M rhs = reflect((k << 1) | 1, len >> 1);
            d[k] = f(lhs, rhs);
        }
    }

public:
    int n, lev;
    vector<M> d;
    vector<OM> lz;
    virtual M f(M, M) = 0;
    virtual M g(M, OM) = 0;
    virtual OM h(OM, OM) = 0;
    virtual OM p(OM, int) = 0;
    const M u1;
    const OM u0;

    LazySegmentTree(M u1, OM u0) : u1(u1), u0(u0) {}

    void build(const vector<M>& v) {
        int _n = v.size();
        init(_n);
        for (int i = 0; i < _n; ++i) d[n + i] = v[i];
        for (int i = n - 1; i > 0; --i) d[i] = f(d[(i << 1) | 0], d[(i << 1) | 1]);
    }
    void build(int _n) { init(_n); }

    // 半開区間 [a, b) に対する更新クエリ (a, b: 0-indexed)
    void update(int a, int b, OM x) {
        thrust(a += n);
        thrust(b += n - 1);
        for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
            if (l & 1) lz[l] = h(lz[l], x), l++;
            if (r & 1) --r, lz[r] = h(lz[r], x);
        }
        recalc(a);
        recalc(b);
    }

    // 半開区間 [a, b) に対する取得クエリ (a, b: 0-indexed)
    M query(int a, int b) {
        thrust(a += n);
        thrust(b += n - 1);
        M L = u1, R = u1;
        for (int l = a, r = b + 1, len = 1; l < r; l >>= 1, r >>= 1, len <<= 1) {
            if (l & 1) L = f(L, reflect(l++, len));
            if (r & 1) R = f(reflect(--r, len), R);
        }
        return f(L, R);
    }
    M query(int a) { return query(a, a + 1); }
};
template <class M = int, class OM = int> using LST = LazySegmentTree<M, OM>;

// RSQ and RAQ
template <class M = int, class OM = int> struct RSQRAQ : LazySegmentTree<M, OM> {
    using LazySegmentTree<M, OM>::LazySegmentTree;
    RSQRAQ() : RSQRAQ(0, 0) {}
    M f(M a, M b) override { return a + b; }
    M g(M a, OM b) override { return a + b; }
    OM h(OM a, OM b) override { return a + b; }
    OM p(OM a, int b) override { return a * b; }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, Q;
    cin >> N >> Q;
    vector<vector<int>> G(N);
    REP (i, N - 1) {
        int a, b;
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    HeavyLightDecomposition HLD(G);
    HLD.build();
    RSQRAQ<int, int> LST;
    LST.build(N);

    REP (i, Q) {
        int c;
        cin >> c;
        if (!c) {
            int u, v;
            cin >> u >> v;
            int ans = 0;
            HLD.for_each_edge(u, v, [&](int l, int r) { ans += LST.query(l, r); });
            cout << ans << endl;
        } else {
            int v, x;
            cin >> v >> x;
            LST.update(HLD.vid[v] + 1, HLD.vid[v] + HLD.sub[v], x);
        }
    }
}


Measured memory_bytes: 41944