#define _CRT_SECURE_NO_WARNINGS
//#define _GLIBCXX_DEBUG
#include <cstdio>
#include <iostream>
#include <vector>
#include <tuple>
#include <stack>
#include <tuple>
#include <set>
#include <queue>
#include <memory>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> pii;
#define all(c) (c).begin(), (c).end()
#define loop(i,a,b) for(ll i=a; i<ll(b); i++)
#define rep(i,b) loop(i,0,b)
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
template<class T> ostream & operator<<(ostream & os, vector<T> const &);
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream &, tuple<T...> const &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream & os, tuple<T...> const & t){ os << (n==0?"":" ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream & operator<<(ostream & os, tuple<T...> const & t){ _ot<0>(os, t); return os; }
template<class T, class U> ostream & operator<<(ostream & os, pair<T,U> const & p){ return os << "(" << p.first << ", " << p.second << ") "; }
template<class T> ostream & operator<<(ostream & os, vector<T> const & v){ rep(i,v.size()) os << v[i] << (i+1==(int)v.size()?"":" "); return os; }
#ifdef DEBUG
#define dump(...) (cerr<<#__VA_ARGS__<<" = "<<mt(__VA_ARGS__)<<" ["<<__LINE__<<"]"<<endl)
#else
#define dump(...)
#endif

#define int ll

typedef int Weight;
struct Edge {
    int src, dst;
    Weight weight;
    int id;
    Edge(int src_, int dst_, Weight weight_, int id_) :
        src(src_), dst(dst_), weight(weight_), id(id_) { }
};
bool operator < (const Edge &e, const Edge &f) {
    return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
        e.src != f.src ? e.src < f.src : e.dst < f.dst;
}
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

namespace segtree_rmq {
    typedef ll dat_t;
    dat_t const inf = (1LL<<31)-1;
    dat_t const init = (1LL<<31)-1;
    struct segment_tree {
        vector<pair<dat_t,int>> dat;
        int n;
        segment_tree(int n_){
            n = 1;
            while(n < n_) n<<=1;
            dat.resize(n*2);
            for(int i=n; i<n+n; i++){
                dat[i] = make_pair(init,i); // -infをdat[i]にするとvectorからのコンストラクタになる
            }
            for(int i=n-1; i>=1; i--){
                dat[i] = min(dat[i<<1], dat[i<<1|1]);
            }
        }
        // bottom-up
        void set(int k, dat_t x){
            int i = n+k; // leaf
            dat[i] = make_pair(x,k);
            while(i != 1){ // 1 is root
                dat[i>>1] = min(dat[i], dat[i^1]);
                i>>=1;
            }
        }
        // top-down
        pair<dat_t,int> get(int a, int b, int k, int l, int r){
            if(r <= a || b <= l) return make_pair(inf,0);
            if(a <= l && r <= b) return dat[k];
            pair<dat_t,int> v1 = get(a,b,k<<1,l,(l+r)/2);
            pair<dat_t,int> v2 = get(a,b,k<<1|1,(l+r)/2,r);
            return min(v1,v2);
        }
        pair<dat_t,int> get(int a, int b){
            return get(a,b,1,0,n);
        }
    };
}

namespace segtree_rangeaddsum {
    typedef ll dat_t;
    struct segment_tree {
        vector<dat_t> partial, overall;
        int n, n_org;
        segment_tree(int n_){
            n = 1;
            n_org = n_;
            while(n < n_) n<<=1;
            partial.assign(n+n,0);
            overall.assign(n+n,0);
        }
        void add(int a, int b, int x, int k, int l, int r){
            if(a <= l && r <= b){
                partial[k] += x;
            } else if(l < b && a < r){
                overall[k] += (min(b,r)-max(a,l)) * x;
                add(a,b,x,k<<1,l,(l+r)/2);
                add(a,b,x,k<<1|1,(l+r)/2,r);
            }
        }
        void add(int a, int b, int x){
            add(a,b,x,1,0,n);
        }
        dat_t sum(int a, int b, int k, int l, int r){
            if(b <= l || r <= a){
                return 0;
            } else if(a <= l && r <= b){
                return partial[k]*(r-l) + overall[k];
            } else {
                dat_t res = (min(b,r)-max(a,l)) * partial[k];
                res += sum(a,b,k<<1,l,(l+r)/2);
                res += sum(a,b,k<<1|1,(l+r)/2,r);
                return res;
            }
        }
        dat_t sum(int a, int b){
            return sum(a,b,1,0,n);
        }
        void view(){
            for(int i=0; i<n_org; i++){
                cout << sum(i,i+1) << " ";
            }
            cout << endl;
        }
    };
}

class LowestCommonAncestor {
public:
    int n;
    LowestCommonAncestor(int n_)
        : n(n_),
          g(n),
          ord(new int[n*2]),
          depth(new int[n*2]),
          id(new int[n]),
          rmq(new segtree_rmq::segment_tree(n*2)) {
    }
    void add_edge(int a, int b, int id){
        g[a].eb(a,b,0,id);
        g[b].eb(b,a,0,id);
    }
    void compile(int root = 0){
        int k = 0;
        dfs(root,-1,0,k);
        for(int i=0;i<k;i++){
            rmq->set(i,depth[i]);
        }
    }
    int lca(int u, int v){
        int a = id[u], b = id[v];
        return ord[rmq->get(min(a,b), max(a,b)+1).second];
    }
    Graph g;
    unique_ptr<int[]> ord, depth, id;
    unique_ptr<segtree_rmq::segment_tree> rmq;
    void dfs(int v, int p, int d, int & k){
        id[v] = k;
        ord[k] = v; depth[k] = d;
        k++;
        for(auto & e : g[v]){
            if(e.dst != p){
                dfs(e.dst, v, d+1, k);
                ord[k] = v; depth[k] = d;
                k++;
            }
        }
    }
};
typedef LowestCommonAncestor LCA;

int const MAX_N = 300010;

Graph g;
int N,Q;
int a[MAX_N], b[MAX_N];
int down_ord[MAX_N], up_ord[MAX_N]; // 辺のID->DFSで何番目に降りられたか/登られたか
int par_edge[MAX_N]; // 頂点のID->親につながる辺のID
int cur_ord; // DFSで今まで何本の辺を通ったか
// pair<ord,edge id>
vector<pair<int,int>> down, up;

void dfs(int v){
    for(auto & e : g[v]){
        down.eb(cur_ord,e.id);
        down_ord[e.id] = cur_ord;
        cur_ord++;

        dfs(e.dst);

        up.eb(cur_ord,e.id);
        up_ord[e.id] = cur_ord;
        cur_ord++;
    }
}

signed main(){
    // 親の方が頂点番号が小さい
    cin >> N >> Q;
    g.assign(N,{});
    down.reserve(N);
    up.reserve(N);
    cur_ord = 0;
    par_edge[0] = -1;
    LCA lca(N);
    rep(i,N-1){
        cin >> a[i] >> b[i];
        if(a[i] > b[i]) swap(a[i],b[i]);
        g[a[i]].eb(a[i],b[i],0,i); // 下向きしか追加しない
        lca.add_edge(a[i],b[i],i);
        par_edge[b[i]] = i;
    }
    lca.compile(0);
    dfs(0);

    segtree_rangeaddsum::segment_tree dtree(down.size()), utree(up.size());

    while(Q--){
        char c;
        cin >> c;
        // lower_bound, upper_boundは手抜き。前計算すればO(1)にできる
        if(c=='0'){
            // 距離
            int u,v;
            cin >> u >> v;
            int p = lca.lca(u,v);
            int res = 0;
            // d(p,u) + d(p,v)
            for(auto & x : {u,v}){
                if(x==p) continue;
                // d(p,x)
                {
                    // DFSで巡った順にp->xへ移動するときの辺の重みの和を求める。
                    // 下る辺を+, 登る辺を-にして足せば、重複が打ち消されて
                    // 直接p->xへ移動するときの和と同じになる
                    int beg = down_ord[g[p].front().id];
                    int en = down_ord[par_edge[x]]+1;
                    {
                        auto l = lower_bound(all(down), mp(beg,-1LL));
                        auto r = upper_bound(all(down), mp(en,-1LL));
                        res += dtree.sum(l-down.begin(), r-down.begin());
                    }
                    {
                        auto l = lower_bound(all(up), mp(beg,-1LL));
                        auto r = upper_bound(all(up), mp(en,-1LL));
                        res -= utree.sum(l-up.begin(), r-up.begin());
                    }
                }
            }
            cout << res << endl;
        } else {
            // 加算
            int v,w;
            cin >> v >> w;
            if(g[v].size()==0) continue;
            {
                auto lb = mp(down_ord[g[v].front().id], -1LL);
                auto ub = mp(up_ord[g[v].back().id]+1, -1LL);
                auto l = lower_bound(all(down), lb);
                auto r = upper_bound(all(down), ub);
                dtree.add(l-down.begin(), r-down.begin(), w);
            }
            {
                auto lb = mp(down_ord[g[v].front().id], -1LL);
                auto ub = mp(up_ord[g[v].back().id]+1, -1LL);
                auto l = lower_bound(all(up), lb);
                auto r = upper_bound(all(up), ub);
                utree.add(l-up.begin(), r-up.begin(), w);
            }
        }
    }
}

Measured memory_bytes: 85380