#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 SparseTable{
  vi val;
  vector<vi> table;

  SparseTable(void){}
  SparseTable(const vi a):val(a){
    int n = a.size(), ln = MSB(n);
    table = vector<vi>(n,vi(ln+1,0));
    rep(i,n)table[i][0] = i;

    int k = 1;
    rep(j,ln){
      rep(i,n){
	int id1 = table[i][j], id2 = (i+k<n)?table[i+k][j]:id1;
	table[i][j+1] = (val[id1]<=val[id2])?id1:id2;
      }
      k <<= 1;
    }
  }

  inline int rmqi(int l, int r){
    int ln = MSB(r-l);
    int id1 = table[l][ln], id2 = table[r-(1<<ln)][ln];
    return (val[id1]<=val[id2])?id1:id2;
  }

  inline int rmq(int l, int r){ return val[rmqi(l,r)]; }
};

struct dif1RMQ{
  int s;
  vi val, subval, subid, bit;
  SparseTable st;
  vector< vector<vi> > lookup_table;

  dif1RMQ(void){}
  dif1RMQ(const vi a):val(a){
    int n = a.size();
    s = max(1,MSB(n)/2);
    int m = (n+s-1)/s;

    subval.resize(m); subid.resize(m); bit.resize(m);
    rep(i,m){
      subval[i] = val[s*i]; subid[i] = s*i;
      int lim = min(s*(i+1),n);
      for(int j=s*i;j<lim;j++){
	if(subval[i] > val[j]){ subval[i] = val[j]; subid[i] = j; }
      }
      bit[i] = 0;
      for(int j=s*i;j<lim-1;j++){
	if(val[j]<val[j+1])bit[i] |= 1<<(j-s*i+1);
      }
    }
    st = SparseTable(subval);

    lookup_table.resize(1<<s);
    rep(i,1<<s)lookup_table[i] = vector<vi>(s, vi(s,0));
      
    rep(i,1<<s)rep(j,s){
      int cur = 0, minv = 0, minid = j;
      lookup_table[i][j][j] = j;
      for(int k=j+1;k<s;k++){
	if( (i>>k)&1 )cur++;
	else cur--;
	if(minv > cur){ minv = cur; minid = k; }
	lookup_table[i][j][k] = minid;
      }
    }
  }

  inline int rmqi(int l, int r){
    r--;
    int bl = l/s, br = r/s;
    if(bl == br)return lookup_table[bit[bl]][l-bl*s][r-br*s] + bl*s;
    else{
      int res = lookup_table[bit[bl]][l-bl*s][s-1] + bl*s;
      int tmp = lookup_table[bit[br]][0][r-br*s] + br*s;
      if(val[res] > val[tmp])res = tmp;

      if(br-bl>1){
	tmp = subid[st.rmqi(bl+1,br)];
	if(val[res] > val[tmp])res = tmp;
      }
      return res;
    }
  }

  inline int rmq(int l, int r){ return val[rmqi(l,r)]; }
};

struct LCA{
  vi tour, depth, id;
  dif1RMQ dr;
  
  LCA(void){}
  LCA(const vector<vi> t,int root){
    int n = t.size(), k = 0;
    tour.resize(2*n-1); depth.resize(2*n-1); id.resize(n);
    dfs(root,-1,0,k,t);
    dr = dif1RMQ(depth);
  }

  inline void dfs(int v,int p, int d, int &k, const vector<vi> &t){
    id[v] = k; tour[k] = v;
    depth[k++] = d;
    for(int u : t[v]){
      if(u != p){
	dfs(u,v,d+1,k,t);
	tour[k] = v;
	depth[k++] = d;
      }
    }
  }

  inline int lca(int u, int v){
    int a = min(id[u],id[v]), b = max(id[u],id[v]);
    return tour[dr.rmqi(a,b+1)];
  }
  inline int dep(int v){ return depth[id[v]]; }
};

//Segment Tree for Range Add and Sum
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);
  }

  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();

  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);
  }

  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,q){
    int x,u,v;
    scanf("%d%d%d",&x,&u,&v);
    if(x==0){
      int w = lca.lca(u,v);
      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();

      st_open.range_add(olp,orp,v);
      st_close.range_add(clp,crp,v);
    }
  }
}

Measured memory_bytes: 43196