#include "iostream"
#include "random"
#include "string"
#include "bitset"
#include "algorithm"
#include "map"
#include "queue"
#include "list"
#include "set"
#include "climits"
#include "iomanip"
#include "stack"
#include "functional"

using namespace std;
using ll = long long int;
using PII = pair<ll, ll>;

struct HLDecomposition {
	int n, pos;
	vector<vector<ll>> g;
	vector<ll> vid,
		head,
		sub,
		hvy,
		par,
		depth,
		inv,
		type,
		ps,
		pt;

	HLDecomposition() {}
	HLDecomposition(int sz) :
		n(sz), pos(0), g(n),
		vid(n, -1), head(n), sub(n, 1), hvy(n, -1),
		par(n), depth(n), inv(n), type(n), ps(n), pt(n) {}

	void add_edge(int u, int v) {
		g[u].push_back(v);
		g[v].push_back(u);
	}
	void build() {
		dfs1(0);
		dfs2(0, 0);
	}

	void dfs1(ll rt) {
		stack<PII> st;
		par[rt] = -1;
		depth[rt] = 0;
		st.emplace(rt, 0);
		while (st.size()) {
			ll v = st.top().first;
			ll &i = st.top().second;
			if (i < (int)g[v].size()) {
				int u = g[v][i++];
				if (u == par[v]) continue;
				par[u] = v;
				depth[u] = depth[v] + 1;
				st.emplace(u, 0);
			}
			else {
				st.pop();
				for (ll &u : g[v]) {
					if (u == par[v]) swap(u, g[v].back());
					if (u == par[v]) continue;
					sub[v] += sub[u];
					if (sub[u] > sub[g[v].front()]) swap(u, g[v].front());
				}
			}
		}
	}
	void dfs2(ll r, ll c) {
		using T = tuple<ll, ll, ll>;
		stack<T> st;
		st.emplace(r, r, 0);
		while (!st.empty()) {
			ll v, h;
			tie(v, h, ignore) = st.top();
			ll &i = get<2>(st.top());
			if (!i) {
				type[v] = c;
				ps[v] = vid[v] = pos++;
				inv[vid[v]] = v;
				head[v] = h;
				hvy[v] = (g[v].empty() ? -1 : g[v][0]);
				if (hvy[v] == par[v]) hvy[v] = -1;
			}
			if (i < (ll)g[v].size()) {
				ll u = g[v][i++];
				if (u == par[v]) continue;
				st.emplace(u, hvy[v] == u ? h : u, 0);
			}
			else {
				st.pop();
				pt[v] = pos;
			}
		}
	}

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

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

template<typename T, typename E>
struct lazySegTree {
	using F = function<T(T, T)>;
	using G = function<T(T, E)>;
	using H = function<E(E, E)>;
	using P = function<E(E, int)>;
	F f; G g; H h; P p; T d1; E d0;
	int n;
	vector<T> dat;
	vector<E> lazy;

	lazySegTree() {}
	lazySegTree(int n_, F f_, G g_, H h_, T d1_, E d0_, P p_) :
		f(f_), g(g_), h(h_), p(p_), d1(d1_), d0(d0_)
	{
		n = 1; while (n < n_) n *= 2;
		dat.assign(n * 2 - 1, d1);
		lazy.assign(n * 2 - 1, d0);
	}
	void build(vector<T> v) {
		for (ll i = 0; i < v.size(); ++i) dat[i + n - 1] = v[i];
		for (int i = n - 2; i >= 0; --i) dat[i] = f(dat[i * 2 + 1], dat[i * 2 + 2]);
	}

	inline void eval(int len, int k) {
		if (lazy[k] == d0) return;
		if (k * 2 + 1 < n * 2 - 1) {
			lazy[2 * k + 1] = h(lazy[k * 2 + 1], lazy[k]);
			lazy[2 * k + 2] = h(lazy[k * 2 + 2], lazy[k]);
		}
		dat[k] = g(dat[k], p(lazy[k], len));
		lazy[k] = d0;
	}
	T update(ll a, ll b, E x, ll k, ll l, ll r) {
		eval(r - l, k);
		if (b <= l || r <= a) return dat[k];
		if (a <= l && r <= b) {
			lazy[k] = h(lazy[k], x);
			return g(dat[k], p(lazy[k], r - l));
		}
		return dat[k] = f(update(a, b, x, 2 * k + 1, l, (l + r) / 2),
			update(a, b, x, 2 * k + 2, (l + r) / 2, r));
	}
	T update(ll a, ll b, E x) { return update(a, b, x, 0, 0, n); }

	T query(ll a, ll b, ll k, ll l, ll r) {
		eval(r - l, k);
		if (a <= l && r <= b) return dat[k];
		bool left = !((l + r) / 2 <= a || b <= l), right = !(r <= 1 || b <= (l + r) / 2);
		if (left&&right) return f(query(a, b, 2 * k + 1, l, (l + r) / 2), query(a, b, 2 * k + 2, (l + r) / 2, r));
		if (left) return query(a, b, 2 * k + 1, l, (l + r) / 2);
		return query(a, b, 2 * k + 2, (l + r) / 2, r);
	}
	T query(ll a, ll b) { return query(a, b, 0, 0, n); }

	void debug() {
		cerr << "--------------" << endl;
		int cnt = 0;
		for (int i = 1; i <= n; i *= 2) {
			for (ll j = 0; j < i; ++j) {
				cerr << "(" << dat[cnt] << "," << lazy[cnt] << ") ";
				cnt++;
			}
			cerr << endl;
		}
		cerr << "-------------" << endl;
	}
};

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);

	ll n, q;
	cin >> n >> q;
	HLDecomposition hld(n);
	for (ll i = 0; i < n - 1; ++i) {
		ll a, b;
		cin >> a >> b;
		hld.add_edge(a, b);
	}
	hld.build();

	auto f = [](ll a, ll b) { return a + b; };
	auto p = [](ll a, int b) { return a*b; };

	lazySegTree<ll, ll> seg(n, f, f, f, 0, 0, p);

	for (ll i = 0; i < q; ++i) {
		ll type, u, v;
		cin >> type >> u >> v;
		if (type == 0) {
			ll ans = 0;
			auto f = [&](ll a, ll b) {
				if (a > b) swap(a, b);
				//cout << "a=" << a << " b=" << b << " " << seg.query(a, b + 1) << endl;
				ans += seg.query(a, b+1);
			};
			hld.for_each_edge(u, v, f);
			cout << ans << endl;
		}
		else {
			auto f = [&](ll a, ll b) {
				if (a > b) swap(a, b);
				//cout << "a=" << a << " b=" << b << endl;
				seg.update(a, b+1, v);
			};

			if (hld.sub[u] == 1) continue;
			ll idx = hld.inv[hld.vid[u] + hld.sub[u] - 1];
			//cout << "u=" << u << " idx=" << idx << endl;
			seg.update(hld.vid[u]+1, hld.vid[u] + hld.sub[u], v);
			//hld.for_each_edge(u, idx, f);
		}

		// seg.debug();
	}
}


Measured memory_bytes: 32128