#include <bits/stdc++.h>
using namespace std;

#define for_(i,a,b) for(int i=(a);i<(b);++i)
#define for_rev(i,a,b) for(int i=(a);i>=(b);--i)
#define allof(a) (a).begin(),(a).end()
#define minit(a,b) memset(a,b,sizeof(a))
#define cauto const auto

typedef long long lint;
typedef pair< int, int > pii;
template< typename T > inline void maxUpdate(T& a, T b) { a = max(a, b); }

template< typename DATA >
class SegmentTreeR {
private:
    int size__;
    vector< DATA > data, adds;
     
    inline int left_t(int k) { return (k << 1) + 1; }
    inline int right_t(int k) { return (k << 1) + 2; }
    inline int center(int l, int r) { return (l + r) >> 1; }
     
public:
    SegmentTreeR() {}
     
    SegmentTreeR(int n, DATA ini, DATA lini) {
        for (size__ = 1; size__ < n; size__ <<= 1);
        data.assign(2 * size__ - 1, ini);
        adds.assign(2 * size__ - 1, lini);
    }
     
    void rangeAdd(int a, int b, DATA x) { rangeAdd(a, b, x, 0, 0, size__); }
     
    void rangeAdd(int a, int b, DATA x, int k, int l, int r) {
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            adds[k] += x;
            return;
        }
         
        data[k] += x * (min(r, b) - max(l, a));
        rangeAdd(a, b, x, left_t(k), l, center(l, r));
        rangeAdd(a, b, x, right_t(k), center(l, r), r);
    }
     
    DATA query(int a, int b) { return query(a, b, 0, 0, size__); }
     
    DATA query(int a, int b, int k, int l, int r) {     
        if (r <= a || b <= l) return 0;
        if (a <= l && r <= b) return data[k] + adds[k] * (r - l);
        return  query(a, b, left_t(k), l, center(l, r))
                + query(a, b, right_t(k), center(l, r), r)
                + adds[k] * (min(r, b) - max(l, a));
    }
     
    int size() {
        return size__;
    }
};

class H_L_Decomp {
public:
	struct Node {
		int parent;
		vector< int > path;
		vector< int > adj;
	};
	
	struct VertexInfo { int nodeID, pos; };
	
	struct Result {
		vector< Node > nodes;
		vector< VertexInfo > vinfo;
	};
	
private:
	int N;
	const vector< vector< int > >& adj;
	
	vector< Node > nodes;
	vector< VertexInfo > vinfo;
	
	vector< int > child_sum;
	vector< pii > part_max;
	
	void partDfs(int v) {
		child_sum[v] = 1;
		
		for (auto& u : adj[v]) {
			partDfs(u);
			child_sum[v] += child_sum[u];
			maxUpdate(part_max[v], pii(child_sum[u], u));
		}
	}
	
	void decompDfs_VerStack(int v) {
		stack< pii > stk;
		stk.push(pii(v, 1));
		
		while (!stk.empty()) {
			pii p = stk.top(); stk.pop();
			int v = p.first, ns = p.second;
			
			vinfo[v].nodeID = ns - 1;
			vinfo[v].pos = nodes[ns - 1].path.size();
			
			nodes[ns - 1].path.push_back(v);
			
			if (part_max[v].second != -1) {
				for (auto& u : adj[v]) {
					if (u != part_max[v].second) {
						nodes[vinfo[v].nodeID].adj.push_back(ns);
						nodes.push_back(Node{v, vector< int >(), vector< int >()});
						
						stk.push(pii(u, nodes.size()));
					}
				}
				
				stk.push(pii(part_max[v].second, ns));
			}
		}
	}
	
	/*
	void decompDfs(int v) {		
		vinfo[v].nodeID = nodes.size() - 1;
		vinfo[v].pos = nodes[ nodes.size() - 1 ].path.size();
		
		nodes[nodes.size() - 1].path.push_back(v);
		
		if (part_max[v].second != -1) {
			decompDfs(part_max[v].second);
			
			for (auto& u : adj[v]) {
				if (u != part_max[v].second) {
					nodes[ vinfo[v].nodeID ].adj.push_back(nodes.size());
					nodes.push_back(Node{v, vector< int >(), vector< int >()});
					
					decompDfs(u);
				}
			}
		}
	}
	*/
	
public:
	H_L_Decomp(const vector< vector< int > >& _adj_) : N(_adj_.size()), adj(_adj_) {}
	
	Result decomposition(int root) {
		child_sum.assign(N, 0);
		part_max.assign(N, pii(-1, -1));
		
		partDfs(root);
		
		child_sum.clear();
		
		nodes.clear();
		nodes.push_back(Node{-1, vector< int >(), vector< int >()});
		
		vinfo = vector< VertexInfo >(N);
		
		decompDfs_VerStack(0);
		//decompDfs(root);
		
		return Result{nodes, vinfo};
	}
};

class LCA {
public:
	struct Result {
		vector< int > depth;
		
		int K;
		vector< vector< int > > parent;
		
		int getLCA(int u, int v) {
			if (depth[u] > depth[v]) swap(u, v);
			
			for_(k,0,K) if ((depth[v] - depth[u]) >> k & 1) v = parent[v][k];
			
			if (u == v) return u;
			
			for_rev(k,K-1,0) {
				if (parent[u][k] != parent[v][k]) {
					u = parent[u][k];
					v = parent[v][k];
				}
			}
			
			return parent[u][0];
		}
	};
	
private:
	int N;
	const vector< vector< int > >& adj;
	
	vector< int > depth;
	vector< vector< int > > parent;
	
	void depthDfs(int v) {
		for (auto& u : adj[v]) {
			parent[u][0] = v;
			depth[u] = depth[v] + 1;
			depthDfs(u);
		}
	}
	
public:
	LCA(const vector< vector< int > >& _adj_) : N(_adj_.size()), adj(_adj_) {}
	
	Result generate(int root) {
		depth.assign(N, 0);
		
		int S = 1, K = 1;
		for (; S < N; S <<= 1) ++K;
		
		parent.assign(N, vector< int >(K, -1));
		
		depthDfs(root);
		
		for_(k,0,K-1) for_(v,0,N) {
			if (parent[v][k] < 0) parent[v][k + 1] = -1;
			else parent[v][k + 1] = parent[ parent[v][k] ][k];
		}
		
		return Result{depth, K, parent};
	}
};

int N, Q;
vector< vector< int > > adj;

LCA::Result lca;

int M;
H_L_Decomp::Result hld;
vector< SegmentTreeR< lint > > segv;

int cur_id;
vector< int > partID;
vector< pii > partRange;
SegmentTreeR< lint > partCost;

void hldDfs(int v) {
	partRange[v].first = cur_id;
	
	for (auto& u : adj[v]) hldDfs(u);
	
	partRange[v].second = cur_id;
	
	if (hld.vinfo[v].pos == 0) {
		partID[ hld.vinfo[v].nodeID ] = cur_id;
		++cur_id;
	}
}

lint getCost(int v) {
	lint res = 0;
	
	while (v >= 0) {
		int t = hld.vinfo[v].nodeID;
		int rgt = hld.vinfo[v].pos;
		res += partCost.query(partID[t], partID[t] + 1) * (rgt + 1);
		res += segv[t].query(0, rgt);
		v = hld.nodes[t].parent;
	}
	
	return res;
}

int main() {
	cin >> N >> Q;
	
	adj.assign(N, vector< int >());
	
	for_(i,0,N-1) {
		int u, v;
		scanf("%d %d", &u, &v);
		adj[u].push_back(v);
	}
	
	lca = LCA(adj).generate(0);
	
	hld = H_L_Decomp(adj).decomposition(0);
	
	M = hld.nodes.size();
	
	for_(i,0,M) segv.push_back(SegmentTreeR< lint >(hld.nodes[i].path.size(), 0, 0));
	
	partID.assign(M, -1);
	partRange.assign(N, pii(0, 0));
	partCost = SegmentTreeR< lint >(M, 0, 0);
	
	cur_id = 0;
	hldDfs(0);
	
	for_(i,0,Q) {
		int q, a, b;
		scanf("%d %d %d", &q, &a, &b);
		
		if (q) {
			int t = hld.vinfo[a].nodeID;
			segv[t].rangeAdd(hld.vinfo[a].pos, hld.nodes[t].path.size(), b);
			partCost.rangeAdd(partRange[a].first, partRange[a].second, b);
		} else {
			int c = lca.getLCA(a, b);
			lint A = getCost(a), B = getCost(b), C = getCost(c);
			cout << A + B - 2 * C << endl;
			//printf("%ld\n", A + B - 2 * C);
		}
	}
}

Measured memory_bytes: 67768