#include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define all(a) (a).begin(), (a).end()
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;

inline int MSB(int x){ return x>0?31-__builtin_clz(x):-1; }

struct LCA{
  vector<vi> par;
  vi depth;
  int ln;
  
  LCA(void){}
  LCA(const vector<vi> t,int root){
    int n = t.size(); ln = MSB(n)+1;
    depth.resize(n); par.resize(ln,vi(n));

    stack< pair<int,int> > s;
    s.push(make_pair(root,-1));
    while(s.size()){
      int v = s.top().first, p = s.top().second; s.pop();
      par[0][v] = p;
      depth[v] = ((p<0)?0:(depth[p]+1));
      for(int u : t[v]){
	if(u != p)s.push(make_pair(u,v));
      }
    }

    rep(k,ln-1)rep(v,n){
      if(par[k][v]<0)par[k+1][v] = -1;
      else par[k+1][v] = par[k][par[k][v]];
    }
  }

  inline int lca(int u, int v){
    if(depth[u] > depth[v])swap(u,v);
    rep(k,ln){
      if((depth[v]-depth[u])>>k & 1)v = par[k][v];
    }
    if(u==v)return u;
    for(int k = ln-1;k>=0;k--){
      if(par[k][u] != par[k][v]){
	u = par[k][u];
	v = par[k][v];
      }
    }
    return par[0][u];
  }
  inline int dep(int v){ return depth[v]; }
};

//Segment Tree for Range Maximum Query
class SegmentTree{
  int n;
  vl all, part;
public:
  SegmentTree(int n_){
    n=1;
    while(n<n_)n*=2;
    all = part = vl(2*n-1,0);
  }
  
  void range_add(int a, int b, ll v, int k=0, int l=0, int r=0){
    if(l>=r)r = n;
    if(r<=a || b<=l)return;
    if(a<=l && r<=b){
      all[k] += v; return;
    }
    part[k] += v * (min(r,b)-max(l,a));
    range_add(a,b,v,2*k+1,l,(l+r)/2);
    range_add(a,b,v,2*k+2,(l+r)/2,r);
  }

  //return maximum value in [a,b). ( [l,r) is interval in which k is.)
  ll range_sum(int a,int b,int k=0,int l=0,int r=0){
    if(l>=r)r = n;
    if(r<=a || b<=l)return 0;
    if(a<=l && r<=b)return all[k]*(r-l) + part[k];
    ll vl = range_sum(a,b,2*k+1,l,(l+r)/2);
    ll vr = range_sum(a,b,2*k+2,(l+r)/2,r);
    return vl + vr + all[k]*(min(r,b)-max(l,a));
  }
};


ll cost(int x, vi &open, vi &pos_open, vi &pos_close,
	SegmentTree &st_open, SegmentTree &st_close){
  int pos = open[x];
  int op = upper_bound(all(pos_open),pos) - pos_open.begin();
  int cp = upper_bound(all(pos_close),pos) - pos_close.begin();

  //cout << x << " " <<  op << " " << cp << endl;
  //cout << st_open.range_sum(0,op) << " " << st_close.range_sum(0,cp) << endl;;

  return st_open.range_sum(0,op) - st_close.range_sum(0,cp);
}

int main(){
  int n,q;
  scanf("%d%d",&n,&q);
  vector<vi> tree(n);
  rep(i,n-1){
    int a,b;
    scanf("%d%d",&a,&b);
    tree[a].push_back(b);
  }
  /*
  rep(i,n){
    for(int u: tree[i])cout << u << " "; cout << endl;
  }
  */

  LCA lca(tree,0);

  int azu=0;
  vi open(n,-1), close(n,-1);
  stack<int> s; s.push(0);
  while(s.size()){
    int v = s.top(); s.pop();
    if(open[v]<0){
      open[v] = azu++;
      s.push(v);
      for(int u : tree[v])s.push(u);
    }else{
      close[v] = azu++;
    }
  }

  vi pos_open = open, pos_close = close;
  sort(all(pos_open)); sort(all(pos_close));

  SegmentTree st_open(n), st_close(n);

  /*
  rep(i,tour.size())cout << tour[i] << " "; cout << endl;
  rep(i,n)cout << open[i] << " "; cout << endl;
  rep(i,n)cout << close[i] << " "; cout << endl;
  */

  rep(i,q){
    int x,u,v;
    scanf("%d%d%d",&x,&u,&v);
    if(x==0){
      int w = lca.lca(u,v);
      //cout << w << endl;
      ll res = cost(u, open, pos_open, pos_close, st_open, st_close)
	+ cost(v, open, pos_open, pos_close, st_open, st_close)
	- 2 * cost(w, open, pos_open, pos_close, st_open, st_close);
      printf("%lld\n",res);
    }else{
      int l = open[u], r = close[u];
      int olp = upper_bound(all(pos_open),l) - pos_open.begin();
      int orp = lower_bound(all(pos_open),r) - pos_open.begin();
      int clp = upper_bound(all(pos_close),l) - pos_close.begin();
      int crp = lower_bound(all(pos_close),r) - pos_close.begin();

      //cout << olp << " " << orp << " " << clp << " " << crp << endl;
      st_open.range_add(olp,orp,v);
      st_close.range_add(clp,crp,v);
    }
  }
}