Problem:
Problem L: Tousa Tree
Problem
君は一昨日、友人のトウサから一つ、頼み事をされた。なんでも、木に等差数列を飾って誕生日パーティーに使いたいのだが、木が大きすぎて一人ではとてもできないのだという。そこで、優秀なプログラマである君に、効率的に木に等差数列を飾るプログラムを書いてもらいたいそうだ。君とトウサは旧知の親友である。君はトウサの頼み事を受けることにした。
飾り付けをする$N$ノードの木が与えられる。木のノードには$0$から$N-1$までの番号が振られている。最初、木のノードの点数は全て$0$である。プログラムは、以下の二つのクエリに対応しなければならない。
$0$.木の指定された区間のノードに書かれた点数の和を求める。
$1$.木の指定された区間のノードに等差数列を足す。
トウサの誕生日を祝うために、木を美しく飾ろう。
Input
入力は以下の形式で与えられる。
$N$ $Q$
$A_0$ $B_0$
$A_1$ $B_1$
:
$A_{N-2}$ $B_{N-2}$
$COM_0$
$COM_1$
:
$COM_{Q-1}$
木のノード数$N$とクエリの数$Q$が$1$行に与えられる。続いて$N-1$行に木の辺の情報が与えられる。$A_i$,$B_i$は、ノード$A_i$と$B_i$の間に直接辺があることを示している。その後、$Q$個の命令$COM_j$が与えられる。
$COM_j$の形式は以下の通りである。
$0$ $S$ $T$
$S$、$T$は頂点の番号である。区間の指定は二つのノードによって行われる。$S$から$T$までの最短経路が指定された区間である。区間に含まれているノードに書かれた点数の総和を報告する。ただし、$S$と$T$も区間に含む。答えは非常に大きくなることがあるので、$10^9+7$で割ったあまりを出力すること。
$1$ $S$ $T$ $K$ $M$
上と同じく、$S$と$T$で指定された区間に含まれているノードに点数を足す。足す点数は、$S$からの最短距離を$L$として、以下のように算出される。
$K+L{\times}M$
Constraints
入力は以下の条件を満たす。
入力はすべては整数
$1 \le N,Q \le 10^5$
$0 \le A,B,S,T \le N-1$
$0 \le K,M \le 10^5$
Output
$0$のクエリのとき、指定された区間に含まれているノードに書かれた点数の総和を一行に出力する。
Sample Input 1
3 3
0 2
1 2
1 1 0 0 1
0 0 2
0 0 1
Sample Output 1
3
3
まず、$1-2-0$の区間に初項$0$、公差$1$の数列を足す。ノードの点数は$0,1,2$の順に$2,0,1$となる。
次に、$0-2$の区間のノードの点数の和を出力する。$2+1=3$なので、$3$を出力する。
次に、$0-2-1$の区間のノードの点数の和を出力する。$2+1+0=3$なので、$3$を出力する。
Sample Input 2
5 6
1 0
2 0
3 2
4 1
1 1 4 0 4
0 4 1
1 3 0 7 3
0 2 2
1 4 1 8 0
0 4 2
Sample Output 2
4
10
43

Submitted solutions:

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

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

#define CHMIN(a,b) (a)=min((a),(b))
#define CHMAX(a,b) (a)=max((a),(b))

#define MOD 1000000007

struct TousaSegmentTree {
  int n;
  vector<ll> sum, lastval;
  vector<ll> rangeadd;
  TousaSegmentTree(int _n){
    n = 1;
    while(n<_n+1)n<<=1;
    sum.assign(2*n-1,0ll);
    lastval.assign(2*n-1,0ll);
    rangeadd.assign(2*n-1,0ll);
  }
  void push(int a, int b, int k){
    (sum[k] += (ll)(b-a) * (b-a+1) / 2 % MOD * rangeadd[k] % MOD) %= MOD;
    (lastval[k] += (ll)(b-a) * rangeadd[k]) %= MOD;
    if(k<n-1){
      (rangeadd[2*k+1] += rangeadd[k]) %= MOD;
      (rangeadd[2*k+2] += rangeadd[k]) %= MOD;
    }
    rangeadd[k] = 0;
  }
  void _add(int l, int r, ll x, int a, int b, int k){
    push(a,b,k);
    if(r<=a || b<=l)return;
    if(l<=a && b<=r){
      (rangeadd[k] += x) %= MOD;
      push(a,b,k);
    }else{
      int m = (a+b)/2;
      _add(l,r,x,a,m,2*k+1);
      _add(l,r,x,m,b,2*k+2);
      (sum[k] = sum[2*k+1] + sum[2*k+2] + lastval[2*k+1]*(b-m)) %= MOD;
      (lastval[k] = lastval[2*k+1] + lastval[2*k+2]) %= MOD;
    }
  }
  void addTousa(int l, int r, ll a, ll b){
    _add(l,l+1,a,0,n,0);
    _add(l+1,r,b,0,n,0);
    _add(r,r+1,MOD-(a+(r-l-1)*b)%MOD,0,n,0);
  }
  ll sumTousa(int l, int r, int a, int b, int k){
    push(a,b,k);
    if(r<=a || b<=l)return 0ll;
    if(l<=a && b<=r){
      return sum[k];
    }else{
      int m = (a+b)/2;
      ll lsum = sumTousa(l,r,a,m,2*k+1);
      ll rsum = sumTousa(l,r,m,b,2*k+2);
      int rcnt = max(0,min(r,b)-max(l,m));
      return (lsum + rsum + lastval[2*k+1]*rcnt) % MOD;
    }
  }
  ll sumTousa(int l, int r){
    return sumTousa(l,r,0,n,0);
  }
};

struct HeavyLightDecomposition {
  int n;
  vector<vector<int>> g;
  vector<int> depth, parent, csize;
  vector<vector<int>> chains;
  vector<int> chainid, chainpos;
  int root = 0;
  HeavyLightDecomposition(int _n){
    n = _n;
    g.resize(n);
    depth.assign(n,-1); parent.assign(n,-1); csize.assign(n,0);
    chainid.assign(n,-1); chainpos.assign(n,-1);
  }
  void add_edge(int a, int b){
    g[a].push_back(b);
    g[b].push_back(a);
  }
  void dfs(int p, int bef, int d){
    depth[p] = d;
    csize[p] = 1;
    for(int to : g[p])if(to!=bef){
      dfs(to, p, d+1);
      parent[to] = p;
      csize[p] += csize[to];
    }
  }
  void dfs2(int p, int bef, int id){
    chainid[p] = id;
    chainpos[p] = chains[id].size();
    chains[id].push_back(p);
    for(int to : g[p])if(to!=bef){
      if(csize[to]*2 >= csize[p]){
        // heavy
        dfs2(to, p, id);
      }else{
        // light
        chains.push_back(vector<int>());
        dfs2(to, p, chains.size()-1);
      }
    }
  }
  void construct(){
    dfs(root,-1,0);
    chains.push_back(vector<int>());
    dfs2(root,-1,0);
  }
  int lca(int a, int b){
    while(a != b){
      if(depth[a] < depth[b])swap(a,b);
      if(chainid[a] == chainid[b])return b;
      if(depth[chains[chainid[a]].front()] < depth[chains[chainid[b]].front()])swap(a,b);
      a = chains[chainid[a]].front();
      a = parent[a];
    }
    return a;
  }
};

int main(){
  int n,q;
  scanf("%d%d",&n,&q);
  HeavyLightDecomposition hld(n);
  REP(i,n-1){
    int a,b;
    scanf("%d%d",&a,&b);
    hld.add_edge(a,b);
  }
  hld.construct();

  vector<TousaSegmentTree> segs;
  REP(i,hld.chains.size()){
    segs.push_back(TousaSegmentTree(hld.chains[i].size()));
  }

  while(q--){
    int typ,s,t;
    scanf("%d%d%d",&typ,&s,&t);
    int lca = hld.lca(s,t);
    if(typ == 0){
      // sum
      ll ans = 0;
      while(true){
        int id = hld.chainid[s];
        if(id == hld.chainid[lca]){
          (ans += segs[id].sumTousa(hld.chainpos[lca], hld.chainpos[s]+1)) %= MOD;
          break;
        }
        (ans += segs[id].sumTousa(0, hld.chainpos[s]+1)) %= MOD;
        s = hld.chains[id].front();
        s = hld.parent[s];
      }
      while(true){
        int id = hld.chainid[t];
        if(id == hld.chainid[lca]){
          (ans += segs[id].sumTousa(hld.chainpos[lca]+1, hld.chainpos[t]+1)) %= MOD;
          break;
        }
        (ans += segs[id].sumTousa(0, hld.chainpos[t]+1)) %= MOD;
        t = hld.chains[id].front();
        t = hld.parent[t];
      }
      printf("%lld\n",ans);
    }else{
      // add
      ll a,b;
      scanf("%lld%lld",&a,&b);
      while(true){
        int id = hld.chainid[s];
        int r = hld.chainpos[s]+1;
        if(id == hld.chainid[lca]){
          int l = hld.chainpos[lca];
          segs[id].addTousa(l, r, (a+(r-l-1)*b)%MOD, MOD-b);
          (a += (r-l)*b) %= MOD;
          break;
        }
        segs[id].addTousa(0, r, (a+(r-1)*b)%MOD, MOD-b);
        (a += r*b) %= MOD;
        s = hld.chains[id].front();
        s = hld.parent[s];
      }
      int rest = hld.depth[t] - hld.depth[lca];
      (a += (rest-1)*b) %= MOD;
      b = MOD-b;
      while(true){
        int id = hld.chainid[t];
        int r = hld.chainpos[t]+1;
        if(t == lca)break;
        if(id == hld.chainid[lca]){
          int l = hld.chainpos[lca] + 1;
          segs[id].addTousa(l, r, (a+(r-l-1)*b)%MOD, MOD-b);
          break;
        }
        segs[id].addTousa(0, r, (a+(r-1)*b)%MOD, MOD-b);
        (a += r*b) %= MOD;
        t = hld.chains[id].front();
        t = hld.parent[t];
      }
    }
  }
  return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 34100
final_rank: 2

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define int ll
using PII = pair<int, int>;
template <typename T> using V = vector<T>;
template <typename T> using VV = vector<V<T>>;
template <typename T> using VVV = vector<VV<T>>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define PB push_back

const ll INF = (1LL<<60);
const int MOD = 1000000007;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }
template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; }
template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); }
template<class S,class T>
ostream &operator <<(ostream& out,const pair<S,T>& a){
  out<<'('<<a.first<<','<<a.second<<')';
  return out;
}
template<class T>
ostream &operator <<(ostream& out,const vector<T>& a){
  out<<'[';
  REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';}
  out<<']';
  return out;
}

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

struct HLDecomposition {
  int n, pos;
  VV<int> g;
  V<int> vid, // HL分解後のグラフでのid
        head, // 頂点が属するheavy-pathのheadのid
         sub, // 部分木のサイズ
         hvy, // heavy-path上での次の頂点のid
         par, // 親のid
       depth, // 深さ
         inv, // HL分解前のグラフのid（添え字が分解後のid）
        type, // 森をHL分解するときの属する木の番号
          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);
  }
  // HL分解の構築を行う
  void build(V<int> rs=V<int>(1,0)) {
    int c=0;
    for(int r: rs) {
      dfs1(r);
      dfs2(r, c++);
    }
  }
  // 根rtからdfsして部分木の大きさ、heavy-edgeの判定などをする
  void dfs1(int rt) {
    stack<PII> st;
    par[rt] = -1;
    depth[rt] = 0;
    st.emplace(rt, 0);
    while(st.size()) {
      int v = st.top().first;
      int &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(int &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());
      	}
      }
    }
  }
  // 根r、c番目の木についてchainについての情報をまとめる
  void dfs2(int r, int c) {
    using T = tuple<int, int, int>;
    stack<T> st;
    st.emplace(r,r,0);
    while(!st.empty()) {
      int v,h;
      tie(v,h,ignore)=st.top();
      int &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<(int)g[v].size()) {
        int u=g[v][i++];
        if(u==par[v]) continue;
        st.emplace(u,(hvy[v]==u?h:u),0);
      } else {
        st.pop();
        pt[v]=pos;
      }
    }
  }
  // 頂点に対する処理 [u,v] 開区間なので注意!!!
  void for_each(int u, int v, const function<void(int,int)>& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      // [max(vid[head[v]],vid[u]), vid[v]] の区間についての操作を行う
      f(max(vid[head[v]], vid[u]), vid[v]);
      if(head[u]!=head[v]) v = par[head[v]];
      else break;
    }
  }
  // 辺に対する処理 [u,v] 開区間なので注意!!!
  void for_each_edge(int u, int v, const function<void(int,int)>& 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;
      }
    }
  }
  // 頂点u, vのLCA
  int lca(int u,int v){
    while(1) {
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v = par[head[v]];
    }
  }
  // 頂点u, vの距離
  int distance(int u, int v){
    return depth[u] + depth[v] - 2*depth[lca(u,v)];
  }
};

/**
* @brief セグメント木
* @details 抽象化した遅延セグメント木\n
* 区間更新区間max d1=d0=INT_MAX f=max(a,b) g=h=(b==INT_MAX?a:b)\n
* 区間加算区間和  d1=d0=0 f=g=h=a+b p=a*b\n
* 区間加算区間min d1=d0=0 f=min(a,b) g=h=a+b\n
* 区間更新区間和  d1=d0=0 f=a+b g=h=(b==0?a:b) p=a*b\n
* 区間xor区間和   d1=d0=0 f=a+b g=(b>=1?b-a:a) h=a^b p=a*b
*/
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_=[](E a, int b){return a;})
    : f(f_), g(g_), h(h_), p(p_), d1(d1_), d0(d0_) 
  {
    n = 1; while(n < n_) n *= 2;
    dat.assign(n*2, d1);
    lazy.assign(n*2, d0);
  }
  void build(vector<T> v) {
    REP(i, v.size()) 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]);
  }

  // 区間の幅がlenの節点kについて遅延評価
  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]);
      E rx = {(lazy[k].first + len/2*lazy[k].second%MOD) % MOD, lazy[k].second};
      lazy[2*k+2] = h(lazy[k*2+2], rx);
    }
    dat[k] = g(dat[k],p(lazy[k],len));
    lazy[k] = d0;
  }
  // [a, b)
  T update(int a, int b, E x, int k, int l, int r) {
    eval(r-l, k);
    if(b <= l || r <= a) return dat[k];
    if(a <= l && r <= b) {
      lazy[k] = h(lazy[k], x);
      eval(r-l, k);
      return dat[k];
    }
    int mid = (l+r)/2;
    bool left = !((l+r)/2 <= a || b <= l), right = !(r <= 1 || b <= (l+r)/2);
    E rx = {(x.first + max(0LL, mid-a)*x.second%MOD)%MOD, x.second};
    if(left&right) { update(a, b, x, 2*k+1, l, mid); update(a, b, rx, 2*k+2, mid, r); }
    else if(left) update(a, b, x, 2*k+1, l, mid);
    else if(right) update(a, b, rx, 2*k+2, mid, r);
    eval(mid-l, 2*k+1); eval(r-mid, 2*k+2);
    return dat[k] = f(dat[2*k+1], dat[2*k+2]);
  }
  T update(int a, int b, E x) { return update(a, b, x, 0, 0, n); }
  // [a, b)
  T query(int a, int b, int k, int l, int 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(int a, int b) { return query(a, b, 0, 0, n); }
  // デバッグ出力
  void debug() {
    cout << "---------------------" << endl;
    int cnt = 0;
    for(int i=1; i<=n; i*=2) {
      REP(j, i) {cout << "(" << dat[cnt] << "," << lazy[cnt] << ") "; cnt++;}
      cout << endl;
    }
    cout << "---------------------" << endl;
  }
};

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

  int n, q;
  cin >> n >> q;
  HLDecomposition hld(n);
  REP(i, n-1) {
    int a, b;
    cin >> a >> b;
    hld.add_edge(a, b);
  }
  hld.build();

  auto f = [&](int a, int b){ return (a+b) % MOD; };
  auto g = [&](int a, PII b){ return (a+b.first) % MOD; };
  auto h = [&](PII a, PII b){ 
    return make_pair((a.first+b.first)%MOD, (a.second+b.second)%MOD);
  };
  auto p = [&](PII a, int b){ 
    return make_pair((a.first*b%MOD + b*(b-1)/2%MOD*a.second%MOD) % MOD, 0LL); 
  };
  lazySegTree<int, PII> seg(n, f, g, h, 0, {0, 0}, p);

  REP(i, q) {
    int type; cin >> type;
    if(type == 0) {
      // sum
      int s, t;
      cin >> s >> t;
      int ans = 0;
      hld.for_each(s, t, [&](int l, int r){
        // cout << "l=" << l << " r=" << r << endl;
        (ans += seg.query(l, r+1)) %= MOD;
      });
      cout << (ans+MOD)%MOD << endl;
    } else {
      // add
      int s, t, a, d;
      cin >> s >> t >> a >> d;
      hld.for_each(s, t, [&](int l, int r){
        // 初項と公差の正負を求める
        int dist1 = hld.distance(s, hld.inv[l]);
        int dist2 = hld.distance(s, hld.inv[r]);
        int ta = (a + dist1 * d % MOD) % MOD;
        int td = d;
        if(dist1 > dist2) td = MOD-d;
        // cout << "l=" << l << " r=" << r << " " << hld.inv[l] << " " << hld.inv[r] << " " << ta << " " << td << endl;
        seg.update(l, r+1, {ta, td});
      });
    }
    // seg.debug();
  }

  return 0;
}
accuracy: 0.14893617021276595
time_ms: 270
memory_kb: 22132
final_rank: 18

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define int ll
using PII = pair<int, int>;
template <typename T> using V = vector<T>;
template <typename T> using VV = vector<V<T>>;
template <typename T> using VVV = vector<VV<T>>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define PB push_back

const ll INF = (1LL<<60);
const int MOD = 1000000007;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }
template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; }
template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); }
template<class S,class T>
ostream &operator <<(ostream& out,const pair<S,T>& a){
  out<<'('<<a.first<<','<<a.second<<')';
  return out;
}
template<class T>
ostream &operator <<(ostream& out,const vector<T>& a){
  out<<'[';
  REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';}
  out<<']';
  return out;
}

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

struct HLDecomposition {
  int n, pos;
  VV<int> g;
  V<int> vid, // HL分解後のグラフでのid
        head, // 頂点が属するheavy-pathのheadのid
         sub, // 部分木のサイズ
         hvy, // heavy-path上での次の頂点のid
         par, // 親のid
       depth, // 深さ
         inv, // HL分解前のグラフのid（添え字が分解後のid）
        type, // 森をHL分解するときの属する木の番号
          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);
  }
  // HL分解の構築を行う
  void build(V<int> rs=V<int>(1,0)) {
    int c=0;
    for(int r: rs) {
      dfs1(r);
      dfs2(r, c++);
    }
  }
  // 根rtからdfsして部分木の大きさ、heavy-edgeの判定などをする
  void dfs1(int rt) {
    stack<PII> st;
    par[rt] = -1;
    depth[rt] = 0;
    st.emplace(rt, 0);
    while(st.size()) {
      int v = st.top().first;
      int &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(int &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());
      	}
      }
    }
  }
  // 根r、c番目の木についてchainについての情報をまとめる
  void dfs2(int r, int c) {
    using T = tuple<int, int, int>;
    stack<T> st;
    st.emplace(r,r,0);
    while(!st.empty()) {
      int v,h;
      tie(v,h,ignore)=st.top();
      int &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<(int)g[v].size()) {
        int u=g[v][i++];
        if(u==par[v]) continue;
        st.emplace(u,(hvy[v]==u?h:u),0);
      } else {
        st.pop();
        pt[v]=pos;
      }
    }
  }
  // 頂点に対する処理 [u,v] 開区間なので注意!!!
  void for_each(int u, int v, const function<void(int,int)>& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      // [max(vid[head[v]],vid[u]), vid[v]] の区間についての操作を行う
      f(max(vid[head[v]], vid[u]), vid[v]);
      if(head[u]!=head[v]) v = par[head[v]];
      else break;
    }
  }
  // 辺に対する処理 [u,v] 開区間なので注意!!!
  void for_each_edge(int u, int v, const function<void(int,int)>& 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;
      }
    }
  }
  // 頂点u, vのLCA
  int lca(int u,int v){
    while(1) {
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v = par[head[v]];
    }
  }
  // 頂点u, vの距離
  int distance(int u, int v){
    return depth[u] + depth[v] - 2*depth[lca(u,v)];
  }
};

/**
* @brief セグメント木
* @details 抽象化した遅延セグメント木\n
* 区間更新区間max d1=d0=INT_MAX f=max(a,b) g=h=(b==INT_MAX?a:b)\n
* 区間加算区間和  d1=d0=0 f=g=h=a+b p=a*b\n
* 区間加算区間min d1=d0=0 f=min(a,b) g=h=a+b\n
* 区間更新区間和  d1=d0=0 f=a+b g=h=(b==0?a:b) p=a*b\n
* 区間xor区間和   d1=d0=0 f=a+b g=(b>=1?b-a:a) h=a^b p=a*b
*/
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_=[](E a, int b){return a;})
    : f(f_), g(g_), h(h_), p(p_), d1(d1_), d0(d0_) 
  {
    n = 1; while(n < n_) n *= 2;
    dat.assign(n*2, d1);
    lazy.assign(n*2, d0);
  }
  void build(vector<T> v) {
    REP(i, v.size()) 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]);
  }

  // 区間の幅がlenの節点kについて遅延評価
  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]);
      E rx = {(lazy[k].first + len/2*lazy[k].second%MOD) % MOD, lazy[k].second};
      lazy[2*k+2] = h(lazy[k*2+2], rx);
    }
    dat[k] = g(dat[k],p(lazy[k],len));
    lazy[k] = d0;
  }
  // [a, b)
  T update(int a, int b, E x, int k, int l, int 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));
    }
    int mid = (l+r)/2;
    E rx = {(x.first + max(0LL, mid-a)*x.second%MOD)%MOD, x.second};
    return dat[k] = f(update(a, b, x, 2*k+1, l, mid),
                      update(a, b, rx, 2*k+2, mid, r));
  }
  T update(int a, int b, E x) { return update(a, b, x, 0, 0, n); }
  // [a, b)
  T query(int a, int b, int k, int l, int 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(int a, int b) { return query(a, b, 0, 0, n); }
  // デバッグ出力
  void debug() {
    cout << "---------------------" << endl;
    int cnt = 0;
    for(int i=1; i<=n; i*=2) {
      REP(j, i) {cout << "(" << dat[cnt] << "," << lazy[cnt] << ") "; cnt++;}
      cout << endl;
    }
    cout << "---------------------" << endl;
  }
};

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

  int n, q;
  cin >> n >> q;
  HLDecomposition hld(n);
  REP(i, n-1) {
    int a, b;
    cin >> a >> b;
    hld.add_edge(a, b);
  }
  hld.build();

  auto f = [&](int a, int b){ return (a+b) % MOD; };
  auto g = [&](int a, PII b){ return (a+b.first) % MOD; };
  auto h = [&](PII a, PII b){ 
    return make_pair((a.first+b.first)%MOD, (a.second+b.second)%MOD);
  };
  auto p = [&](PII a, int b){ 
    return make_pair((a.first*b%MOD + b*(b-1)/2%MOD*a.second%MOD) % MOD, 0LL); 
  };
  lazySegTree<int, PII> seg(n, f, g, h, 0, {0, 0}, p);

  REP(i, q) {
    int type; cin >> type;
    if(type == 0) {
      // sum
      int s, t;
      cin >> s >> t;
      int ans = 0;
      hld.for_each(s, t, [&](int l, int r){
        (ans += seg.query(l, r+1)) %= MOD;
      });
      cout << (ans+MOD)%MOD << endl;
    } else {
      // add
      int s, t, a, d;
      cin >> s >> t >> a >> d;
      hld.for_each(s, t, [&](int l, int r){
        // 初項と公差の正負を求める
        int dist1 = hld.distance(s, hld.inv[l]);
        int dist2 = hld.distance(s, hld.inv[r]);
        int ta = (a + dist1 * d % MOD) % MOD;
        int td = d;
        if(dist1 > dist2) td = MOD-d;
        // cout << "l=" << l << " r=" << r << " " << ta << " " << td << endl;
        seg.update(l, r+1, {ta, td});
      });
    }

    // seg.debug();
  }

  return 0;
}
accuracy: 0.14893617021276595
time_ms: 270
memory_kb: 21948
final_rank: 17

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define int ll
using PII = pair<int, int>;
template <typename T> using V = vector<T>;
template <typename T> using VV = vector<V<T>>;
template <typename T> using VVV = vector<VV<T>>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define PB push_back

const ll INF = (1LL<<60);
const int MOD = 1000000007;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }
template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; }
template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); }
template<class S,class T>
ostream &operator <<(ostream& out,const pair<S,T>& a){
  out<<'('<<a.first<<','<<a.second<<')';
  return out;
}
template<class T>
ostream &operator <<(ostream& out,const vector<T>& a){
  out<<'[';
  REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';}
  out<<']';
  return out;
}

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

struct HLDecomposition {
  int n, pos;
  VV<int> g;
  V<int> vid, // HL分解後のグラフでのid
        head, // 頂点が属するheavy-pathのheadのid
         sub, // 部分木のサイズ
         hvy, // heavy-path上での次の頂点のid
         par, // 親のid
       depth, // 深さ
         inv, // HL分解前のグラフのid（添え字が分解後のid）
        type, // 森をHL分解するときの属する木の番号
          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);
  }
  // HL分解の構築を行う
  void build(V<int> rs=V<int>(1,0)) {
    int c=0;
    for(int r: rs) {
      dfs1(r);
      dfs2(r, c++);
    }
  }
  // 根rtからdfsして部分木の大きさ、heavy-edgeの判定などをする
  void dfs1(int rt) {
    stack<PII> st;
    par[rt] = -1;
    depth[rt] = 0;
    st.emplace(rt, 0);
    while(st.size()) {
      int v = st.top().first;
      int &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(int &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());
      	}
      }
    }
  }
  // 根r、c番目の木についてchainについての情報をまとめる
  void dfs2(int r, int c) {
    using T = tuple<int, int, int>;
    stack<T> st;
    st.emplace(r,r,0);
    while(!st.empty()) {
      int v,h;
      tie(v,h,ignore)=st.top();
      int &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<(int)g[v].size()) {
        int u=g[v][i++];
        if(u==par[v]) continue;
        st.emplace(u,(hvy[v]==u?h:u),0);
      } else {
        st.pop();
        pt[v]=pos;
      }
    }
  }
  // 頂点に対する処理 [u,v] 開区間なので注意!!!
  void for_each(int u, int v, const function<void(int,int)>& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      // [max(vid[head[v]],vid[u]), vid[v]] の区間についての操作を行う
      f(max(vid[head[v]], vid[u]), vid[v]);
      if(head[u]!=head[v]) v = par[head[v]];
      else break;
    }
  }
  // 辺に対する処理 [u,v] 開区間なので注意!!!
  void for_each_edge(int u, int v, const function<void(int,int)>& 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;
      }
    }
  }
  // 頂点u, vのLCA
  int lca(int u,int v){
    while(1) {
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v = par[head[v]];
    }
  }
  // 頂点u, vの距離
  int distance(int u, int v){
    return depth[u] + depth[v] - 2*depth[lca(u,v)];
  }
};

/**
* @brief セグメント木
* @details 抽象化した遅延セグメント木\n
* 区間更新区間max d1=d0=INT_MAX f=max(a,b) g=h=(b==INT_MAX?a:b)\n
* 区間加算区間和  d1=d0=0 f=g=h=a+b p=a*b\n
* 区間加算区間min d1=d0=0 f=min(a,b) g=h=a+b\n
* 区間更新区間和  d1=d0=0 f=a+b g=h=(b==0?a:b) p=a*b\n
* 区間xor区間和   d1=d0=0 f=a+b g=(b>=1?b-a:a) h=a^b p=a*b
*/
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_=[](E a, int b){return a;})
    : f(f_), g(g_), h(h_), p(p_), d1(d1_), d0(d0_) 
  {
    n = 1; while(n < n_) n *= 2;
    dat.assign(n*2, d1);
    lazy.assign(n*2, d0);
  }
  void build(vector<T> v) {
    REP(i, v.size()) 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]);
  }

  // 区間の幅がlenの節点kについて遅延評価
  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]);
      E rx = {(lazy[k].first + len/2*lazy[k].second%MOD) % MOD, lazy[k].second};
      lazy[2*k+2] = h(lazy[k*2+2], rx);
    }
    dat[k] = g(dat[k],p(lazy[k],len));
    lazy[k] = d0;
  }
  // [a, b)
  T update(int a, int b, E x, int k, int l, int 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));
    }
    int mid = (l+r)/2;
    E rx = {(x.first + max(0LL, mid-a)*x.second%MOD)%MOD, x.second};
    return dat[k] = f(update(a, b, x, 2*k+1, l, mid),
                      update(a, b, rx, 2*k+2, mid, r));
  }
  T update(int a, int b, E x) { return update(a, b, x, 0, 0, n); }
  // [a, b)
  T query(int a, int b, int k, int l, int 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(int a, int b) { return query(a, b, 0, 0, n); }
  // デバッグ出力
  void debug() {
    cout << "---------------------" << endl;
    int cnt = 0;
    for(int i=1; i<=n; i*=2) {
      REP(j, i) {cout << "(" << dat[cnt] << "," << lazy[cnt] << ") "; cnt++;}
      cout << endl;
    }
    cout << "---------------------" << endl;
  }
};

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

  int n, q;
  cin >> n >> q;
  HLDecomposition hld(n);
  REP(i, n-1) {
    int a, b;
    cin >> a >> b;
    hld.add_edge(a, b);
  }
  hld.build();

  auto f = [&](int a, int b){ return (a+b) % MOD; };
  auto g = [&](int a, PII b){ return (a+b.first) % MOD; };
  auto h = [&](PII a, PII b){ 
    return make_pair((a.first+b.first)%MOD, (a.second+b.second)%MOD);
  };
  auto p = [&](PII a, int b){ 
    return make_pair((a.first*b%MOD + b*(b-1)/2%MOD*a.second%MOD) % MOD, 0LL); 
  };
  lazySegTree<int, PII> seg(n, f, g, h, 0, {0, 0}, p);

  REP(i, q) {
    int type; cin >> type;
    if(type == 0) {
      // sum
      int s, t;
      cin >> s >> t;
      int ans = 0;
      hld.for_each(s, t, [&](int l, int r){
        (ans += seg.query(l, r+1)) %= MOD;
      });
      cout << (ans+MOD)%MOD << endl;
    } else {
      // add
      int s, t, a, d;
      cin >> s >> t >> a >> d;
      hld.for_each(s, t, [&](int l, int r){
        // 初項と公差の正負を求める
        int dist1 = hld.distance(s, hld.inv[l]);
        int dist2 = hld.distance(s, hld.inv[r]);
        int ta = a + dist1 * d;
        int td = d;
        if(dist1 > dist2) td *= -1;
        // cout << "l=" << l << " r=" << r << " " << ta << " " << td << endl;
        seg.update(l, r+1, {ta, td});
      });
    }

    // seg.debug();
  }

  return 0;
}
accuracy: 0.14893617021276595
time_ms: 280
memory_kb: 21944
final_rank: 19

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define int ll
using PII = pair<int, int>;
template <typename T> using V = vector<T>;
template <typename T> using VV = vector<V<T>>;
template <typename T> using VVV = vector<VV<T>>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define PB push_back

const ll INF = (1LL<<60);
const int MOD = 1000000007;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }
template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; }
template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); }
template<class S,class T>
ostream &operator <<(ostream& out,const pair<S,T>& a){
  out<<'('<<a.first<<','<<a.second<<')';
  return out;
}
template<class T>
ostream &operator <<(ostream& out,const vector<T>& a){
  out<<'[';
  REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';}
  out<<']';
  return out;
}

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

struct HLDecomposition {
  int n, pos;
  VV<int> g;
  V<int> vid, // HL分解後のグラフでのid
        head, // 頂点が属するheavy-pathのheadのid
         sub, // 部分木のサイズ
         hvy, // heavy-path上での次の頂点のid
         par, // 親のid
       depth, // 深さ
         inv, // HL分解前のグラフのid（添え字が分解後のid）
        type, // 森をHL分解するときの属する木の番号
          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);
  }
  // HL分解の構築を行う
  void build(V<int> rs=V<int>(1,0)) {
    int c=0;
    for(int r: rs) {
      dfs1(r);
      dfs2(r, c++);
    }
  }
  // 根rtからdfsして部分木の大きさ、heavy-edgeの判定などをする
  void dfs1(int rt) {
    stack<PII> st;
    par[rt] = -1;
    depth[rt] = 0;
    st.emplace(rt, 0);
    while(st.size()) {
      int v = st.top().first;
      int &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(int &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());
      	}
      }
    }
  }
  // 根r、c番目の木についてchainについての情報をまとめる
  void dfs2(int r, int c) {
    using T = tuple<int, int, int>;
    stack<T> st;
    st.emplace(r,r,0);
    while(!st.empty()) {
      int v,h;
      tie(v,h,ignore)=st.top();
      int &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<(int)g[v].size()) {
        int u=g[v][i++];
        if(u==par[v]) continue;
        st.emplace(u,(hvy[v]==u?h:u),0);
      } else {
        st.pop();
        pt[v]=pos;
      }
    }
  }
  // 頂点に対する処理 [u,v] 開区間なので注意!!!
  void for_each(int u, int v, const function<void(int,int)>& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      // [max(vid[head[v]],vid[u]), vid[v]] の区間についての操作を行う
      f(max(vid[head[v]], vid[u]), vid[v]);
      if(head[u]!=head[v]) v = par[head[v]];
      else break;
    }
  }
  // 辺に対する処理 [u,v] 開区間なので注意!!!
  void for_each_edge(int u, int v, const function<void(int,int)>& 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;
      }
    }
  }
  // 頂点u, vのLCA
  int lca(int u,int v){
    while(1) {
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v = par[head[v]];
    }
  }
  // 頂点u, vの距離
  int distance(int u, int v){
    return depth[u] + depth[v] - 2*depth[lca(u,v)];
  }
};

/**
* @brief セグメント木
* @details 抽象化した遅延セグメント木\n
* 区間更新区間max d1=d0=INT_MAX f=max(a,b) g=h=(b==INT_MAX?a:b)\n
* 区間加算区間和  d1=d0=0 f=g=h=a+b p=a*b\n
* 区間加算区間min d1=d0=0 f=min(a,b) g=h=a+b\n
* 区間更新区間和  d1=d0=0 f=a+b g=h=(b==0?a:b) p=a*b\n
* 区間xor区間和   d1=d0=0 f=a+b g=(b>=1?b-a:a) h=a^b p=a*b
*/
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_=[](E a, int b){return a;})
    : f(f_), g(g_), h(h_), p(p_), d1(d1_), d0(d0_) 
  {
    n = 1; while(n < n_) n *= 2;
    dat.assign(n*2, d1);
    lazy.assign(n*2, d0);
  }
  void build(vector<T> v) {
    REP(i, v.size()) 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]);
  }

  // 区間の幅がlenの節点kについて遅延評価
  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]);
      E rx = {(lazy[k].first + len/2*lazy[k].second%MOD) % MOD, lazy[k].second};
      lazy[2*k+2] = h(lazy[k*2+2], rx);
    }
    dat[k] = g(dat[k],p(lazy[k],len));
    lazy[k] = d0;
  }
  // [a, b)
  T update(int a, int b, E x, int k, int l, int 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));
    }
    int mid = (l+r)/2;
    E rx = {(x.first + max(0LL, mid-a)*x.second%MOD)%MOD, x.second};
    return dat[k] = f(update(a, b, x, 2*k+1, l, mid),
                      update(a, b, rx, 2*k+2, mid, r));
  }
  T update(int a, int b, E x) { return update(a, b, x, 0, 0, n); }
  // [a, b)
  T query(int a, int b, int k, int l, int 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(int a, int b) { return query(a, b, 0, 0, n); }
  // デバッグ出力
  void debug() {
    cout << "---------------------" << endl;
    int cnt = 0;
    for(int i=1; i<=n; i*=2) {
      REP(j, i) {cout << "(" << dat[cnt] << "," << lazy[cnt] << ") "; cnt++;}
      cout << endl;
    }
    cout << "---------------------" << endl;
  }
};

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

  int n, q;
  cin >> n >> q;
  HLDecomposition hld(n);
  REP(i, n-1) {
    int a, b;
    cin >> a >> b;
    hld.add_edge(a, b);
  }
  hld.build();

  auto f = [&](int a, int b){ return (a+b) % MOD; };
  auto g = [&](int a, PII b){ return (a+b.first) % MOD; };
  auto h = [&](PII a, PII b){ 
    return make_pair((a.first+b.first)%MOD, (a.second+b.second)%MOD);
  };
  auto p = [&](PII a, int b){ 
    return make_pair((a.first*b%MOD + b*(b-1)/2%MOD*a.second%MOD) % MOD, 0LL); 
  };
  lazySegTree<int, PII> seg(n, f, g, h, 0, {0, 0}, p);

  REP(i, q) {
    int type; cin >> type;
    if(type == 0) {
      // sum
      int s, t;
      cin >> s >> t;
      int ans = 0;
      hld.for_each(s, t, [&](int l, int r){
        (ans += seg.query(l, r+1)) %= MOD;
      });
      cout << ans << endl;
    } else {
      // add
      int s, t, a, d;
      cin >> s >> t >> a >> d;
      hld.for_each(s, t, [&](int l, int r){
        // 初項と公差の正負を求める
        int dist1 = hld.distance(s, hld.inv[l]);
        int dist2 = hld.distance(s, hld.inv[r]);
        int ta = a + dist1 * d;
        int td = d;
        if(dist1 > dist2) td *= -1;
        // cout << "l=" << l << " r=" << r << " " << ta << " " << td << endl;
        seg.update(l, r+1, {ta, td});
      });
    }

    // seg.debug();
  }

  return 0;
}
accuracy: 0.14893617021276595
time_ms: 280
memory_kb: 22000
final_rank: 20

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;

struct HLDecomposition {
  int n,pos;
  vector<vector<int> > G;
  vector<int> vid, head, sub, par, dep, inv, type;
  
  HLDecomposition(){}
  HLDecomposition(int n):
    n(n),pos(0),G(n),vid(n,-1),head(n),sub(n,1),
    par(n,-1),dep(n,0),inv(n),type(n){}
  
  void add_edge(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }

  void build(vector<int> rs={0}) {
    int c=0;
    for(int r:rs){
      dfs_sz(r);
      head[r]=r;
      dfs_hld(r,c++);
    }
  }
  
  void dfs_sz(int v) {
    for(int &u:G[v]){
      if(u==par[v]) continue;
      par[u]=v;
      dep[u]=dep[v]+1;
      dfs_sz(u);      
      sub[v]+=sub[u];      
      if(sub[u]>sub[G[v][0]]) swap(u,G[v][0]);
    }
  }

  void dfs_hld(int v,int c) {
    vid[v]=pos++;
    inv[vid[v]]=v;
    type[v]=c;
    for(int u:G[v]){
      if(u==par[v]) continue;
      head[u]=(u==G[v][0]?head[v]:u);
      dfs_hld(u,c);
    }    
  }
  
  // for_each(vertex)
  // [l,r] <- attention!!  
  template<typename F>
  void for_each(int u, int v, const F& 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;
    }
  }

  template<typename T,typename Q,typename F>
  T for_each(int u,int v,T ti,const Q &q,const F &f){
    T l=ti,r=ti;
    while(1){
      if(vid[u]>vid[v]){
	swap(u,v);
	swap(l,r);
      }
      l=f(l,q(max(vid[head[v]],vid[u]),vid[v]));
      if(head[u]!=head[v]) v=par[head[v]];
      else break;
    }
    return f(l,r);
  }
  
  // for_each(edge)
  // [l,r] <- attention!!
  template<typename F>
  void for_each_edge(int u, int v,const F& 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;
      }
    }
  }
  
  int lca(int u,int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v=par[head[v]];
    }
  }

  int distance(int u,int v){
    return dep[u]+dep[v]-2*dep[lca(u,v)];
  }
};


template <typename T,typename E>
struct SegmentTree{
  using F = function<T(T,T)>;
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  SegmentTree(int n_,F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){init(n_);}
  void init(int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
  }
  void build(int n_, vector<T> v){
    for(int i=0;i<n_;i++) dat[n+i]=v[i];
    for(int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  T reflect(int k){
    return g(dat[k],laz[k]);
  }
  inline void eval(int k){
    if(laz[k]==ei) return;
    laz[(k<<1)|0]=h(laz[(k<<1)|0],laz[k]);
    laz[(k<<1)|1]=h(laz[(k<<1)|1],laz[k]);
    dat[k]=reflect(k);
    laz[k]=ei;
  }
  void update(int a,int b,E x){
    a+=n;b+=n-1;
    for(int i=height;i;i--) eval(a>>i);
    for(int i=height;i;i--) eval(b>>i);
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1){
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    while(a>>=1)
      dat[a]=f(reflect((a<<1)|0),reflect((a<<1)|1));
    while(b>>=1)
      dat[b]=f(reflect((b<<1)|0),reflect((b<<1)|1));
  }
  T query(int a,int b){
    a+=n;b+=n-1;
    for(int i=height;i;i--) eval(a>>i);
    for(int i=height;i;i--) eval(b>>i);
    T vl=ti,vr=ti;
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,reflect(l++));
      if(r&1) vr=f(reflect(--r),vr);
    }
    return f(vl,vr);
  }
};


template<int MOD = 1000000007>
struct Mint{
  int v;
  Mint():v(0){}
  Mint(int v):v(v){}
  Mint(int v,bool f):v(v){if(f) v%=MOD;}

  Mint pow(int k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }
  
  Mint inv(){return pow(MOD-2);}
  
  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}
  
  Mint operator+(Mint a){return Mint(v)+=a;};
  Mint operator-(Mint a){return Mint(v)-=a;};
  Mint operator*(Mint a){return Mint(v)*=a;};
  Mint operator/(Mint a){return Mint(v)/=a;};

  Mint operator-(){return v?MOD-v:v;}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  
  vector<Mint> fact(int n){
    vector<Mint> res(n+1,1);
    for(int i=1;i<=n;i++) res[i]=res[i-1]*Mint(i);
    return res;
  }
  
  vector<Mint> finv(int n){
    vector<Mint> res(n+1,1);
    for(int i=1;i<=n;i++) res[i]=res[i-1]*Mint(i);
    res[n]=Mint(1)/res[n];
    for(int i=n;i>=1;i--) res[i-1]=res[i]*Mint(i);
    return res;
  }

  vector<Mint> invs(vector<Mint> &a,vector<Mint> &b){
    int n=a.size()-1;
    vector<Mint> res(n+1,0);
    for(int i=1;i<=n;i++) res[i]=b[i]*a[i-1];
    return res;
  }
};

template<int MOD>
istream& operator>>(istream &is, Mint<MOD>& a){
  is>>a.v;
  return is;
} 
template<int MOD>
ostream& operator<<(ostream &os, Mint<MOD>& a){
  os<<a.v;
  return os;
} 

//INSERT ABOVE HERE
const int MOD = 1e9+7;
signed main(){  
  using M = Mint<MOD>;
  
  int n,q;
  scanf("%d %d",&n,&q);
  
  HLDecomposition hld(n);
  for(int i=1;i<n;i++){
    int a,b;
    scanf("%d %d",&a,&b);
    hld.add_edge(a,b);
  }
  hld.build();

  
  struct T{
    int l,r;
    M s;
    T(){}
    T(int l,int r,M s):l(l),r(r),s(s){};
  };
  
  struct P{
    M a,b;
    P(){}
    P(M a,M b):a(a),b(b){};
    bool operator==(const P &x)const{return a==x.a&&b==x.b;}
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  auto f=[&](T a,T b){return T(a.l,b.r,a.s+b.s);};
  auto g=[&](T a,P b){
	   M k(a.r-a.l);
	   M t(1LL*(a.r-a.l)*(a.r-a.l-1)/2,1);
	   b.b=(b.b+M(a.l)*b.a)*k;
	   a.s+=t*b.a+b.b;
	   return a;
	 };
  auto h=[&](P a,P b){return P(a.a+b.a,a.b+b.b);};
  
  SegmentTree<T, P> seg(n,f,g,h,T(-1,-1,M()),P(M(),M()));
  vector<T> vt(n);
  for(int i=0;i<n;i++) vt[hld.vid[i]]=T(hld.dep[i],hld.dep[i]+1,0);
  seg.build(n,vt);
  
  for(int i=0;i<q;i++){
    int c,s,t;
    scanf("%d %d %d",&c,&s,&t);
    int l=hld.lca(s,t);
    
    if(c==1){
      M b,a;
      scanf("%d %d",&b.v,&a.v);
      M up=b-M(hld.dep[s])*-a;
      M dw=b+M(hld.distance(s,t))*a-M(hld.dep[t])*a;
      hld.for_each(l,s,[&](int l,int r){seg.update(l,r+1,P(-a,up));});
      hld.for_each_edge(l,t,[&](int l,int r){seg.update(l,r+1,P(a,dw));});      
    }else{      
      auto ask=[&](int l,int r){return seg.query(l,r+1);};
      T ans=hld.for_each(s,t,T(0,0,0),ask,f);
      printf("%d\n",ans.s.v);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 1200
memory_kb: 22052
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;

struct HLDecomposition {
  int n,pos;
  vector<vector<int> > G;
  vector<int> vid, head, sub, par, dep, inv, type;
  
  HLDecomposition(){}
  HLDecomposition(int n):
    n(n),pos(0),G(n),vid(n,-1),head(n),sub(n,1),
    par(n,-1),dep(n,0),inv(n),type(n){}
  
  void add_edge(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }

  void build(vector<int> rs={0}) {
    int c=0;
    for(int r:rs){
      dfs_sz(r);
      head[r]=r;
      dfs_hld(r,c++);
    }
  }
  
  void dfs_sz(int v) {
    for(int &u:G[v]){
      if(u==par[v]) continue;
      par[u]=v;
      dep[u]=dep[v]+1;
      dfs_sz(u);      
      sub[v]+=sub[u];      
      if(sub[u]>sub[G[v][0]]) swap(u,G[v][0]);
    }
  }

  void dfs_hld(int v,int c) {
    vid[v]=pos++;
    inv[vid[v]]=v;
    type[v]=c;
    for(int u:G[v]){
      if(u==par[v]) continue;
      head[u]=(u==G[v][0]?head[v]:u);
      dfs_hld(u,c);
    }    
  }
  
  // for_each(vertex)
  // [l,r] <- attention!!  
  template<typename F>
  void for_each(int u, int v, const F& 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;
    }
  }

  template<typename T,typename Q,typename F>
  T for_each(int u,int v,T ti,const Q &q,const F &f){
    T l=ti,r=ti;
    while(1){
      if(vid[u]>vid[v]){
	swap(u,v);
	swap(l,r);
      }
      l=f(l,q(max(vid[head[v]],vid[u]),vid[v]));
      if(head[u]!=head[v]) v=par[head[v]];
      else break;
    }
    return f(l,r);
  }
  
  // for_each(edge)
  // [l,r] <- attention!!
  template<typename F>
  void for_each_edge(int u, int v,const F& 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;
      }
    }
  }
  
  int lca(int u,int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v=par[head[v]];
    }
  }

  int distance(int u,int v){
    return dep[u]+dep[v]-2*dep[lca(u,v)];
  }
};


template <typename T,typename E>
struct SegmentTree{
  using F = function<T(T,T)>;
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  SegmentTree(int n_,F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){init(n_);}
  void init(int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
  }
  void build(int n_, vector<T> v){
    for(int i=0;i<n_;i++) dat[n+i]=v[i];
    for(int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  T reflect(int k){
    return g(dat[k],laz[k]);
  }
  inline void eval(int k){
    if(laz[k]==ei) return;
    laz[(k<<1)|0]=h(laz[(k<<1)|0],laz[k]);
    laz[(k<<1)|1]=h(laz[(k<<1)|1],laz[k]);
    dat[k]=reflect(k);
    laz[k]=ei;
  }
  void update(int a,int b,E x){
    a+=n;b+=n-1;
    for(int i=height;i;i--) eval(a>>i);
    for(int i=height;i;i--) eval(b>>i);
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1){
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    while(a>>=1)
      dat[a]=f(reflect((a<<1)|0),reflect((a<<1)|1));
    while(b>>=1)
      dat[b]=f(reflect((b<<1)|0),reflect((b<<1)|1));
  }
  T query(int a,int b){
    a+=n;b+=n-1;
    for(int i=height;i;i--) eval(a>>i);
    for(int i=height;i;i--) eval(b>>i);
    T vl=ti,vr=ti;
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,reflect(l++));
      if(r&1) vr=f(reflect(--r),vr);
    }
    return f(vl,vr);
  }
};


template<int MOD = 1000000007>
struct Mint{
  int v;
  Mint():v(0){}
  Mint(int v):v(v){}
  Mint(int v,bool f):v(v){if(f) v%=MOD;}

  Mint pow(int k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }
  
  Mint inv(){return pow(MOD-2);}
  
  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}
  
  Mint operator+(Mint a){return Mint(v)+=a;};
  Mint operator-(Mint a){return Mint(v)-=a;};
  Mint operator*(Mint a){return Mint(v)*=a;};
  Mint operator/(Mint a){return Mint(v)/=a;};

  Mint operator-(){return v?MOD-v:v;}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  
  vector<Mint> fact(int n){
    vector<Mint> res(n+1,1);
    for(int i=1;i<=n;i++) res[i]=res[i-1]*Mint(i);
    return res;
  }
  
  vector<Mint> finv(int n){
    vector<Mint> res(n+1,1);
    for(int i=1;i<=n;i++) res[i]=res[i-1]*Mint(i);
    res[n]=Mint(1)/res[n];
    for(int i=n;i>=1;i--) res[i-1]=res[i]*Mint(i);
    return res;
  }

  vector<Mint> invs(vector<Mint> &a,vector<Mint> &b){
    int n=a.size()-1;
    vector<Mint> res(n+1,0);
    for(int i=1;i<=n;i++) res[i]=b[i]*a[i-1];
    return res;
  }
};

template<int MOD>
istream& operator>>(istream &is, Mint<MOD>& a){
  is>>a.v;
  return is;
} 
template<int MOD>
ostream& operator<<(ostream &os, Mint<MOD>& a){
  os<<a.v;
  return os;
} 

//INSERT ABOVE HERE
signed main(){  
  constexpr int MOD = 1e9+7;
  using M = Mint<MOD>;
  
  int n,q;
  scanf("%d %d",&n,&q);
  
  HLDecomposition hld(n);
  for(int i=1;i<n;i++){
    int a,b;
    scanf("%d %d",&a,&b);
    hld.add_edge(a,b);
  }
  hld.build();

  
  struct T{
    int l,r;
    M s;
    T(){}
    T(int l,int r,M s):l(l),r(r),s(s){};
  };
  
  struct P{
    M a,b;
    P(){}
    P(M a,M b):a(a),b(b){};
    bool operator==(const P &x)const{return a==x.a&&b==x.b;}
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  auto f=[&](T a,T b){return T(a.l,b.r,a.s+b.s);};
  auto g=[&](T a,P b){
	   M k(a.r-a.l);
	   M t(1LL*(a.r-a.l)*(a.r-a.l-1)/2,1);
	   b.b=(b.b+M(a.l)*b.a)*k;
	   a.s+=t*b.a+b.b;
	   return a;
	 };
  auto h=[&](P a,P b){return P(a.a+b.a,a.b+b.b);};
  
  SegmentTree<T, P> seg(n,f,g,h,T(-1,-1,M()),P(M(),M()));
  vector<T> vt(n);
  for(int i=0;i<n;i++) vt[hld.vid[i]]=T(hld.dep[i],hld.dep[i]+1,0);
  seg.build(n,vt);
  
  for(int i=0;i<q;i++){
    int c,s,t;
    scanf("%d %d %d",&c,&s,&t);
    int l=hld.lca(s,t);
    
    if(c==1){
      M b,a;
      scanf("%d %d",&b.v,&a.v);
      M up=b-M(hld.dep[s])*-a;
      M dw=b+M(hld.distance(s,t))*a-M(hld.dep[t])*a;
      hld.for_each(l,s,[&](int l,int r){seg.update(l,r+1,P(-a,up));});
      hld.for_each_edge(l,t,[&](int l,int r){seg.update(l,r+1,P(a,dw));});      
    }else{      
      auto ask=[&](int l,int r){return seg.query(l,r+1);};
      T ans=hld.for_each(s,t,T(0,0,0),ask,f);
      printf("%d\n",ans.s.v);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 1210
memory_kb: 22056
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;

struct HLDecomposition {
  Int n,pos;
  vector<vector<Int> > G;
  vector<Int> vid, head, sub, hvy, par, dep, inv, type;
  
  HLDecomposition(){}
  HLDecomposition(Int sz):
    n(sz),pos(0),G(n),
    vid(n,-1),head(n),sub(n,1),hvy(n,-1),
    par(n),dep(n),inv(n),type(n){}
  
  void add_edge(Int u, Int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }

  void build(vector<Int> rs={0}) {
    Int c=0;
    for(Int r:rs){
      dfs(r);
      bfs(r, c++);
    }
  }
  
  void dfs(Int rt) {
    using T = pair<Int, Int>;
    stack<T> st;
    par[rt]=-1;
    dep[rt]=0;
    st.emplace(rt,0);
    while(!st.empty()){
      Int v=st.top().first;
      Int &i=st.top().second;
      if(i<(Int)G[v].size()){
	Int u=G[v][i++];
	if(u==par[v]) continue;
	par[u]=v;
	dep[u]=dep[v]+1;
	st.emplace(u,0);
      }else{
	st.pop();
	for(Int j=0;j<(Int)G[v].size();j++){
	  Int &u=G[v][j];
	  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 bfs(Int r,Int c) {
    using T = tuple<Int, Int, Int>;
    stack<T> st;
    st.emplace(r,r,0);
    while(!st.empty()){
      Int v,h;
      tie(v,h,ignore)=st.top();
      Int &i=get<2>(st.top());
      if(!i){
	type[v]=c;
	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<(Int)G[v].size()){
	Int u=G[v][i++];
	if(u==par[v]) continue;
	st.emplace(u,(hvy[v]==u?h:u),0);
      }else{
	st.pop();
      }
    }
  }
  
  // for_each(vertex)
  // [l,r] <- attention!!  
  template<typename F>
  void for_each(Int u, Int v, const F& 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;
    }
  }

  template<typename T,typename Q,typename F>
  T for_each(Int u,Int v,T ti,const Q &q,const F &f){
    T l=ti,r=ti;
    while(1){
      if(vid[u]>vid[v]){
	swap(u,v);
	swap(l,r);
      }
      l=f(l,q(max(vid[head[v]],vid[u]),vid[v]));
      if(head[u]!=head[v]) v=par[head[v]];
      else break;
    }
    return f(l,r);
  }
  
  // for_each(edge)
  // [l,r] <- attention!!
  template<typename F>
  void for_each_edge(Int u, Int v,const F& 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;
      }
    }
  }

  Int lca(Int u,Int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v=par[head[v]];
    }
  }

  Int distance(Int u,Int v){
    return dep[u]+dep[v]-2*dep[lca(u,v)];
  }
};


template <typename T,typename E>
struct SegmentTree{
  using F = function<T(T,T)>;
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  Int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  SegmentTree(Int n_,F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){init(n_);}
  void init(Int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
  }
  void build(Int n_, vector<T> v){
    for(Int i=0;i<n_;i++) dat[n+i]=v[i];
    for(Int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  T reflect(Int k){
    return g(dat[k],laz[k]);
  }
  inline void eval(Int k){
    if(laz[k]==ei) return;
    laz[(k<<1)|0]=h(laz[(k<<1)|0],laz[k]);
    laz[(k<<1)|1]=h(laz[(k<<1)|1],laz[k]);
    dat[k]=reflect(k);
    laz[k]=ei;
  }
  void update(Int a,Int b,E x){
    a+=n;b+=n-1;
    for(Int i=height;i;i--) eval(a>>i);
    for(Int i=height;i;i--) eval(b>>i);
    for(Int l=a,r=b+1;l<r;l>>=1,r>>=1){
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    while(a>>=1)
      dat[a]=f(reflect((a<<1)|0),reflect((a<<1)|1));
    while(b>>=1)
      dat[b]=f(reflect((b<<1)|0),reflect((b<<1)|1));
  }
  T query(Int a,Int b){
    a+=n;b+=n-1;
    for(Int i=height;i;i--) eval(a>>i);
    for(Int i=height;i;i--) eval(b>>i);
    T vl=ti,vr=ti;
    for(Int l=a,r=b+1;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,reflect(l++));
      if(r&1) vr=f(reflect(--r),vr);
    }
    return f(vl,vr);
  }
};

//INSERT ABOVE HERE

const Int MOD = 1e9+7;

signed main(){
  Int n,q;
  scanf("%lld %lld",&n,&q);
  
  HLDecomposition hld(n);
  for(Int i=1;i<n;i++){
    Int a,b;
    scanf("%lld %lld",&a,&b);
    hld.add_edge(a,b);
  }
  hld.build();
  
  auto add=[](Int a,Int b){return (a+b)%MOD;};
  auto mul=[](Int a,Int b){return (a*b)%MOD;};

  struct T{
    Int l,r,s;
    T(){}
    T(Int l,Int r,Int s):l(l),r(r),s(s){};
  };
  struct P{
    Int a,b;
    P(){}
    P(Int a,Int b):a(a),b(b){};
    bool operator==(const P &x)const{return a==x.a&&b==x.b;}
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  
  auto f=[&](T a,T b){return T(a.l,b.r,add(a.s,b.s));};
  auto g=[&](T a,P b){
	   Int k=a.r-a.l;
	   b.b=add(b.b,a.l*b.a)*k;
	   a.s=add(a.s,add(mul(k*(k-1)/2%MOD,b.a),b.b));
	   return a;
	 };
  auto h=[&](P a,P b){return P(add(a.a,b.a),add(a.b,b.b));};

  SegmentTree<T, P> seg(n,f,g,h,T(-1,-1,0),P(0,0));
  vector<T> vt(n);
  for(Int i=0;i<n;i++) vt[hld.vid[i]]=T(hld.dep[i],hld.dep[i]+1,0);
  seg.build(n,vt);
  
  for(Int i=0;i<q;i++){
    Int c,s,t;
    scanf("%lld %lld %lld",&c,&s,&t);
    Int l=hld.lca(s,t);
    
    if(c==1){
      Int b,a;
      scanf("%lld %lld",&b,&a);
      Int up=(b+MOD-hld.dep[s]*(MOD-a)%MOD)%MOD;
      Int dw=(b+hld.distance(s,t)*a%MOD+MOD-hld.dep[t]*a%MOD)%MOD;      
      hld.for_each(l,s,[&](Int l,Int r){seg.update(l,r+1,P(MOD-a,up));});
      hld.for_each_edge(l,t,[&](Int l,Int r){seg.update(l,r+1,P(a,dw));});      
    }else{      
      auto ask=[&](Int l,Int r){return seg.query(l,r+1);};
      T ans=hld.for_each(s,t,T(0,0,0),ask,f);
      printf("%lld\n",(ans.s+MOD)%MOD);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 890
memory_kb: 29720
final_rank: 7

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

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

#define CHMIN(a,b) (a)=min((a),(b))
#define CHMAX(a,b) (a)=max((a),(b))

#define MOD 1000000007

struct TousaSegmentTree {
  int n;
  vector<ll> sum, lastval;
  vector<ll> rangeadd;
  TousaSegmentTree(int _n){
    n = 1;
    while(n<_n+1)n<<=1;
    sum.assign(2*n-1,0ll);
    lastval.assign(2*n-1,0ll);
    rangeadd.assign(2*n-1,0ll);
  }
  void push(int a, int b, int k){
    (sum[k] += (ll)(b-a) * (b-a+1) / 2 % MOD * rangeadd[k] % MOD) %= MOD;
    (lastval[k] += (ll)(b-a) * rangeadd[k]) %= MOD;
    if(k<n-1){
      (rangeadd[2*k+1] += rangeadd[k]) %= MOD;
      (rangeadd[2*k+2] += rangeadd[k]) %= MOD;
    }
    rangeadd[k] = 0;
  }
  void _add(int l, int r, ll x, int a, int b, int k){
    push(a,b,k);
    if(r<=a || b<=l)return;
    if(l<=a && b<=r){
      (rangeadd[k] += x) %= MOD;
      push(a,b,k);
    }else{
      int m = (a+b)/2;
      _add(l,r,x,a,m,2*k+1);
      _add(l,r,x,m,b,2*k+2);
      (sum[k] = sum[2*k+1] + sum[2*k+2] + lastval[2*k+1]*(b-m)) %= MOD;
      (lastval[k] = lastval[2*k+1] + lastval[2*k+2]) %= MOD;
    }
  }
  void addTousa(int l, int r, ll a, ll b){
    _add(l,l+1,a,0,n,0);
    _add(l+1,r,b,0,n,0);
    _add(r,r+1,MOD-(a+(r-l-1)*b)%MOD,0,n,0);
  }
  ll sumTousa(int l, int r, int a, int b, int k){
    push(a,b,k);
    if(r<=a || b<=l)return 0ll;
    if(l<=a && b<=r){
      return sum[k];
    }else{
      int m = (a+b)/2;
      ll lsum = sumTousa(l,r,a,m,2*k+1);
      ll rsum = sumTousa(l,r,m,b,2*k+2);
      int rcnt = max(0,min(r,b)-max(l,m));
      return (lsum + rsum + lastval[2*k+1]*rcnt) % MOD;
    }
  }
  ll sumTousa(int l, int r){
    return sumTousa(l,r,0,n,0);
  }
};

struct HeavyLightDecomposition {
  int n;
  vector<vector<int>> g;
  vector<int> depth, parent, csize;
  vector<vector<int>> chains;
  vector<int> chainid, chainpos;
  int root = 0;
  HeavyLightDecomposition(int _n){
    n = _n;
    g.resize(n);
    depth.assign(n,-1); parent.assign(n,-1); csize.assign(n,0);
    chainid.assign(n,-1); chainpos.assign(n,-1);
  }
  void add_edge(int a, int b){
    g[a].push_back(b);
    g[b].push_back(a);
  }
  void dfs(int p, int bef, int d){
    depth[p] = d;
    csize[p] = 1;
    for(int to : g[p])if(to!=bef){
      dfs(to, p, d+1);
      parent[to] = p;
      csize[p] += csize[to];
    }
  }
  void dfs2(int p, int bef, int id){
    chainid[p] = id;
    chainpos[p] = chains[id].size();
    chains[id].push_back(p);
    for(int to : g[p])if(to!=bef){
      if(csize[to]*2 >= csize[p]){
        // heavy
        dfs2(to, p, id);
      }else{
        // light
        chains.push_back(vector<int>());
        dfs2(to, p, chains.size()-1);
      }
    }
  }
  void construct(){
    dfs(root,-1,0);
    chains.push_back(vector<int>());
    dfs2(root,-1,0);
  }
  int lca(int a, int b){
    while(a != b){
      if(depth[a] < depth[b])swap(a,b);
      if(chainid[a] == chainid[b])return b;
      if(depth[chains[chainid[a]].front()] < depth[chains[chainid[b]].front()])swap(a,b);
      a = chains[chainid[a]].front();
      a = parent[a];
    }
    return a;
  }
};

int main(){
  int n,q;
  scanf("%d%d",&n,&q);
  HeavyLightDecomposition hld(n);
  REP(i,n-1){
    int a,b;
    scanf("%d%d",&a,&b);
    hld.add_edge(a,b);
  }
  hld.construct();

  vector<TousaSegmentTree> segs;
  REP(i,hld.chains.size()){
    segs.push_back(TousaSegmentTree(hld.chains[i].size()));
  }

  while(q--){
    int typ,s,t;
    scanf("%d%d%d",&typ,&s,&t);
    int lca = hld.lca(s,t);
    if(typ == 0){
      // sum
      ll ans = 0;
      while(true){
        int id = hld.chainid[s];
        if(id == hld.chainid[lca]){
          (ans += segs[id].sumTousa(hld.chainpos[lca], hld.chainpos[s]+1)) %= MOD;
          break;
        }
        (ans += segs[id].sumTousa(0, hld.chainpos[s]+1)) %= MOD;
        s = hld.chains[id].front();
        s = hld.parent[s];
      }
      while(true){
        int id = hld.chainid[t];
        if(id == hld.chainid[lca]){
          (ans += segs[id].sumTousa(hld.chainpos[lca]+1, hld.chainpos[t]+1)) %= MOD;
          break;
        }
        (ans += segs[id].sumTousa(0, hld.chainpos[t]+1)) %= MOD;
        t = hld.chains[id].front();
        t = hld.parent[t];
      }
      printf("%lld\n",ans);
    }else{
      // add
      ll a,b;
      scanf("%lld%lld",&a,&b);
      while(true){
        int id = hld.chainid[s];
        int r = hld.chainpos[s]+1;
        if(id == hld.chainid[lca]){
          int l = hld.chainpos[lca];
          segs[id].addTousa(l, r, (a+(r-l-1)*b)%MOD, MOD-b);
          (a += (r-l)*b) %= MOD;
          break;
        }
        segs[id].addTousa(0, r, (a+(r-1)*b)%MOD, MOD-b);
        (a += r*b) %= MOD;
        s = hld.chains[id].front();
        s = hld.parent[s];
      }
      int rest = hld.depth[t] - hld.depth[lca];
      (a += (rest-1)*b) %= MOD;
      b = MOD-b;
      while(true){
        int id = hld.chainid[t];
        int r = hld.chainpos[t]+1;
        if(t == lca)break;
        if(id == hld.chainid[lca]){
          int l = hld.chainpos[lca] + 1;
          segs[id].addTousa(l, r, (a+(r-l-1)*b)%MOD, MOD-b);
          break;
        }
        segs[id].addTousa(0, r, (a+(r-1)*b)%MOD, MOD-b);
        (a += r*b) %= MOD;
        t = hld.chains[id].front();
        t = hld.parent[t];
      }
    }
  }
  return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 36580
final_rank: 5

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

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

#define CHMIN(a,b) (a)=min((a),(b))
#define CHMAX(a,b) (a)=max((a),(b))

#define MOD 1000000007

struct TousaSegmentTree {
  int n;
  vector<ll> sum, lastval;
  vector<ll> rangeadd;
  TousaSegmentTree(int _n){
    n = 1;
    while(n<_n+1)n<<=1;
    sum.assign(2*n-1,0ll);
    lastval.assign(2*n-1,0ll);
    rangeadd.assign(2*n-1,0ll);
  }
  void push(int a, int b, int k){
    (sum[k] += (ll)(b-a) * (b-a+1) / 2 % MOD * rangeadd[k] % MOD) %= MOD;
    (lastval[k] += (ll)(b-a) * rangeadd[k]) %= MOD;
    if(k<n-1){
      (rangeadd[2*k+1] += rangeadd[k]) %= MOD;
      (rangeadd[2*k+2] += rangeadd[k]) %= MOD;
    }
    rangeadd[k] = 0;
  }
  void _add(int l, int r, ll x, int a, int b, int k){
    push(a,b,k);
    if(r<=a || b<=l)return;
    if(l<=a && b<=r){
      (rangeadd[k] += x) %= MOD;
      push(a,b,k);
    }else{
      int m = (a+b)/2;
      _add(l,r,x,a,m,2*k+1);
      _add(l,r,x,m,b,2*k+2);
      (sum[k] = sum[2*k+1] + sum[2*k+2] + lastval[2*k+1]*(b-m)) %= MOD;
      (lastval[k] = lastval[2*k+1] + lastval[2*k+2]) %= MOD;
    }
  }
  void addTousa(int l, int r, ll a, ll b){
    _add(l,l+1,a,0,n,0);
    _add(l+1,r,b,0,n,0);
    _add(r,r+1,-a-(r-l-1)*b,0,n,0);
  }
  ll sumTousa(int l, int r, int a, int b, int k){
    push(a,b,k);
    if(r<=a || b<=l)return 0ll;
    if(l<=a && b<=r){
      return sum[k];
    }else{
      int m = (a+b)/2;
      ll lsum = sumTousa(l,r,a,m,2*k+1);
      ll rsum = sumTousa(l,r,m,b,2*k+2);
      int rcnt = max(0,min(r,b)-max(l,m));
      return (lsum + rsum + lastval[2*k+1]*rcnt) % MOD;
    }
  }
  ll sumTousa(int l, int r){
    return sumTousa(l,r,0,n,0);
  }
};

struct HeavyLightDecomposition {
  int n;
  vector<vector<int>> g;
  vector<int> depth, parent, csize;
  vector<vector<int>> chains;
  vector<int> chainid, chainpos;
  int root = 0;
  HeavyLightDecomposition(int _n){
    n = _n;
    g.resize(n);
    depth.assign(n,-1); parent.assign(n,-1); csize.assign(n,0);
    chainid.assign(n,-1); chainpos.assign(n,-1);
  }
  void add_edge(int a, int b){
    g[a].push_back(b);
    g[b].push_back(a);
  }
  void dfs(int p, int bef, int d){
    depth[p] = d;
    csize[p] = 1;
    for(int to : g[p])if(to!=bef){
      dfs(to, p, d+1);
      parent[to] = p;
      csize[p] += csize[to];
    }
  }
  void dfs2(int p, int bef, int id){
    chainid[p] = id;
    chainpos[p] = chains[id].size();
    chains[id].push_back(p);
    for(int to : g[p])if(to!=bef){
      if(csize[to]*2 >= csize[p]){
        // heavy
        dfs2(to, p, id);
      }else{
        // light
        chains.push_back(vector<int>());
        dfs2(to, p, chains.size()-1);
      }
    }
  }
  void construct(){
    dfs(root,-1,0);
    chains.push_back(vector<int>());
    dfs2(root,-1,0);
  }
  int lca(int a, int b){
    while(a != b){
      if(depth[a] < depth[b])swap(a,b);
      if(chainid[a] == chainid[b])return b;
      if(depth[chains[chainid[a]].front()] < depth[chains[chainid[b]].front()])swap(a,b);
      a = chains[chainid[a]].front();
      a = parent[a];
    }
    return a;
  }
};

int main(){
  int n,q;
  scanf("%d%d",&n,&q);
  HeavyLightDecomposition hld(n);
  REP(i,n-1){
    int a,b;
    scanf("%d%d",&a,&b);
    hld.add_edge(a,b);
  }
  hld.construct();

  vector<TousaSegmentTree> segs;
  REP(i,hld.chains.size()){
    segs.push_back(TousaSegmentTree(hld.chains[i].size()));
  }

  while(q--){
    int typ,s,t;
    scanf("%d%d%d",&typ,&s,&t);
    int lca = hld.lca(s,t);
    if(typ == 0){
      // printf("%d: %d %d\n",typ,s,t);
      // sum
      ll ans = 0;
      while(true){
        int id = hld.chainid[s];
        if(id == hld.chainid[lca]){
          (ans += segs[id].sumTousa(hld.chainpos[lca], hld.chainpos[s]+1)) %= MOD;
          break;
        }
        (ans += segs[id].sumTousa(0, hld.chainpos[s]+1)) %= MOD;
        s = hld.chains[id].front();
        s = hld.parent[s];
      }
      while(true){
        int id = hld.chainid[t];
        if(id == hld.chainid[lca]){
          (ans += segs[id].sumTousa(hld.chainpos[lca]+1, hld.chainpos[t]+1)) %= MOD;
          break;
        }
        (ans += segs[id].sumTousa(0, hld.chainpos[t]+1)) %= MOD;
        t = hld.chains[id].front();
        t = hld.parent[t];
      }
      printf("%lld\n",ans);
    }else{
      // add
      ll a,b;
      scanf("%lld%lld",&a,&b);
      // printf("%d: %d %d %lld %lld\n",typ,s,t,a,b);
      while(true){
        int id = hld.chainid[s];
        int r = hld.chainpos[s]+1;
        if(id == hld.chainid[lca]){
          int l = hld.chainpos[lca];
          segs[id].addTousa(l, r, (a+(r-l-1)*b)%MOD, MOD-b);
          (a += (r-l)*b) %= MOD;
          break;
        }
        segs[id].addTousa(0, r, (a+(r-1)*b)%MOD, MOD-b);
        (a += r*b) %= MOD;
        s = hld.chains[id].front();
        s = hld.parent[s];
      }
      int rest = hld.depth[t] - hld.depth[lca];
      (a += (rest-1)*b) %= MOD;
      b = MOD-b;
      while(true){
        int id = hld.chainid[t];
        int r = hld.chainpos[t]+1;
        if(t == lca)break;
        if(id == hld.chainid[lca]){
          int l = hld.chainpos[lca] + 1;
          segs[id].addTousa(l, r, (a+(r-l-1)*b)%MOD, MOD-b);
          break;
        }
        segs[id].addTousa(0, r, (a+(r-1)*b)%MOD, MOD-b);
        (a += r*b) %= MOD;
        t = hld.chains[id].front();
        t = hld.parent[t];
      }
    }
  }
  return 0;
}
accuracy: 0.3404255319148936
time_ms: 240
memory_kb: 36244
final_rank: 15

code_snippet: #include <limits>
#include <stack>
#include <algorithm>
#include <string>
#include <vector>
#include <functional>
#include <iostream>
#include <queue>
#include <iterator>
#include <cstdint>
#include <utility>
#include <type_traits>
#include <cstddef>
namespace loquat {
template <int MOD>
class modulus_integer {
public:
	typedef modulus_integer<MOD> self_type;
private:
	int m_value;
	static self_type unsafe_construct(int x) noexcept {
		self_type y;
		y.m_value = x;
		return y;
	}
public:
	modulus_integer() noexcept
		: m_value(0)
	{ }
	modulus_integer(int x) noexcept
		: m_value(x % MOD)
	{
		if(m_value < 0){ m_value += MOD; }
	}
	int operator*() const noexcept { return m_value; }
	self_type& operator=(const self_type& x) noexcept {
		m_value = x.m_value;
		return *this;
	}
	self_type operator-() const noexcept {
		return unsafe_construct(m_value > 0 ? MOD - m_value : 0);
	}
	self_type operator+(const self_type& x) const noexcept {
		const int y = m_value + x.m_value;
		return unsafe_construct(y >= MOD ? y - MOD : y);
	}
	self_type operator*(const self_type& x) const noexcept {
		return unsafe_construct(
			static_cast<long long>(m_value) * x.m_value % MOD);
	}
};
template <int MOD>
inline std::ostream& operator<<(
	std::ostream& os, const modulus_integer<MOD>& x)
{
	os << *x;
	return os;
}
}
namespace loquat {
namespace bitmanip {
template <typename T>
inline auto clz(T x) noexcept ->
	typename std::enable_if<sizeof(int) < sizeof(T), unsigned int>::type
{
	return __builtin_clzll(x);
}
template <typename T>
inline T clp2(T x) noexcept {
	if(x == 0u){ return 0u; }
	return T(1u) << (sizeof(T) * 8u - clz(x - 1));
}
}
}
namespace loquat {
template <typename Impl>
class lazy_range_query_behavior_wrapper {
public:
	using value_type = typename Impl::value_type;
	using modifier_type = typename Impl::modifier_type;
private:
	template <typename T>
	struct no_reverse_value {
	private:
		static std::true_type check_unary(...);
		static std::true_type check_binary(...);
	public:
		static const bool value =
			decltype(check_unary(std::declval<T>()))::value &&
			decltype(check_binary(std::declval<T>()))::value;
	};
	Impl m_impl;
	template <typename T>
	static auto split_modifier_helper(
		const T& impl, const modifier_type& m, size_t k)
		-> decltype(impl.split_modifier(m, k))
	{
		return impl.split_modifier(m, k);
	}
	template <typename T>
	static auto modify_helper(
		const T& impl, size_t n, const value_type& v, const modifier_type& m)
		-> decltype(impl.modify(n, v, m))
	{
		return impl.modify(n, v, m);
	}
	template <typename T>
	static auto reverse_value_helper(const T&, size_t, const value_type& x)
		-> typename std::enable_if<no_reverse_value<T>::value, value_type>::type
	{
		return x;
	}
	template <typename T>
	static auto reverse_modifier_helper(const T& impl, size_t n, const modifier_type& m)
		-> decltype(impl.reverse_modifier(n, m))
	{
		return impl.reverse_modifier(n, m);
	}
public:
	lazy_range_query_behavior_wrapper(Impl impl) : m_impl(std::move(impl)) { }
	value_type identity_value() const {
		return m_impl.identity_value();
	}
	modifier_type identity_modifier() const {
		return m_impl.identity_modifier();
	}
	std::pair<modifier_type, modifier_type>
	split_modifier(const modifier_type& m, size_t k) const {
		return split_modifier_helper(m_impl, m, k);
	}
	modifier_type merge_modifier(
		const modifier_type& a, const modifier_type& b) const
	{
		return m_impl.merge_modifier(a, b);
	}
	value_type merge_value(
		const value_type& a, const value_type& b) const
	{
		return m_impl.merge_value(a, b);
	}
	value_type modify(size_t n, const value_type& v, const modifier_type& m) const {
		return modify_helper(m_impl, n, v, m);
	}
	value_type reverse_value(size_t n, const value_type& m) const {
		return reverse_value_helper(m_impl, n, m);
	}
	modifier_type reverse_modifier(size_t n, const modifier_type& m) const {
		return reverse_modifier_helper(m_impl, n, m);
	}
};
}
namespace loquat {
template <typename Behavior>
class lazy_segment_tree {
public:
	using behavior_type = Behavior;
	using value_type = typename behavior_type::value_type;
	using modifier_type = typename behavior_type::modifier_type;
private:
	size_t m_actual_size;
	std::vector<value_type> m_values;
	std::vector<modifier_type> m_modifiers;
	lazy_range_query_behavior_wrapper<behavior_type> m_behavior;
	void initialize(){
		const int n = m_values.size() / 2;
		for(int i = n - 1; i >= 0; --i){
			m_values[i] = m_behavior.merge_value(
				m_values[i * 2 + 1], m_values[i * 2 + 2]);
		}
	}
	value_type modify(
		size_t a, size_t b, size_t k, size_t l, size_t r,
		const modifier_type& modifier)
	{
		if(r <= a || b <= l){
			return m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		}else if(a <= l && r <= b){
			m_modifiers[k] =
				m_behavior.merge_modifier(m_modifiers[k], modifier);
			return m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		}
		const size_t c = l + (r - l) / 2;
		const size_t lk = k * 2 + 1, rk = lk + 1;
		const auto mp = m_behavior.split_modifier(m_modifiers[k], c - l);
		m_modifiers[k] = m_behavior.identity_modifier();
		modify(l, c, lk, l, c, mp.first);
		modify(c, r, rk, c, r, mp.second);
		const auto mq = (a < c)
			? m_behavior.split_modifier(modifier, c - std::max(a, l))
			: std::make_pair(m_behavior.identity_modifier(), modifier);
		const auto vl = modify(a, b, lk, l, c, mq.first);
		const auto vr = modify(a, b, rk, c, r, mq.second);
		m_values[k] = m_behavior.merge_value(vl, vr);
		return m_values[k];
	}
	value_type query(size_t a, size_t b, size_t k, size_t l, size_t r){
		if(r <= a || b <= l){
			return m_behavior.identity_value();
		}else if(a <= l && r <= b){
			return m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		}
		const size_t c = l + (r - l) / 2;
		const size_t lk = k * 2 + 1, rk = k * 2 + 2;
		const auto mp = m_behavior.split_modifier(m_modifiers[k], c - l);
		m_values[k] = m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		m_modifiers[k] = m_behavior.identity_modifier();
		modify(l, c, lk, l, c, mp.first);
		modify(c, r, rk, c, r, mp.second);
		const auto vl = query(a, b, lk, l, c);
		const auto vr = query(a, b, rk, c, r);
		return m_behavior.merge_value(vl, vr);
	}
public:
	lazy_segment_tree(
		size_t size,
		const behavior_type& behavior = behavior_type())
		: m_actual_size(size)
		, m_values(bitmanip::clp2(size) * 2 - 1, behavior.identity_value())
		, m_modifiers(m_values.size(), behavior.identity_modifier())
		, m_behavior(behavior)
	{
		initialize();
	}
	void modify(size_t left, size_t right, const modifier_type& modifier){
		const auto clp2_n = (m_values.size() + 1) / 2;
		modify(left, right, 0, 0, clp2_n, modifier);
	}
	value_type query(size_t left, size_t right){
		const auto clp2_n = (m_values.size() + 1) / 2;
		return query(left, right, 0, 0, clp2_n);
	}
};
}
namespace loquat {
using vertex_t = size_t;
}
namespace loquat {
namespace edge_param {
struct to_ {
	vertex_t to;
	explicit to_(vertex_t t = 0)
		: to(t)
	{ }
};
}
namespace detail {
template <typename T, typename... Params>
struct edge_param_wrapper : public T, edge_param_wrapper<Params...> {
};
template <typename T>
struct edge_param_wrapper<T> : public T {
	template <typename U>
	explicit edge_param_wrapper(U&& x)
		: T(std::forward<U>(x))
	{ }
};
}
template <typename... Params>
struct edge : public detail::edge_param_wrapper<edge_param::to_, Params...> {
	template <typename... Args>
	explicit edge(Args&&... args)
		: detail::edge_param_wrapper<edge_param::to_, Params...>(
			std::forward<Args>(args)...)
	{ }
};
}
namespace loquat {
template <typename EdgeType>
class adjacency_list {
public:
	using edge_type = EdgeType;
	using edge_list = std::vector<edge_type>;
private:
	std::vector<std::vector<EdgeType>> m_edges;
public:
	explicit adjacency_list(size_t n)
		: m_edges(n)
	{ }
	size_t size() const {
		return m_edges.size();
	}
	const edge_list& operator[](vertex_t u) const {
		return m_edges[u];
	}
	template <typename... Args>
	void add_edge(vertex_t from, Args&&... args){
		m_edges[from].emplace_back(std::forward<Args>(args)...);
	}
};
}
namespace loquat {
template <typename EdgeType, typename F>
void breadth_first_search(
	const adjacency_list<EdgeType>& g,
	vertex_t root,
	std::vector<bool>& vis,
	F func)
{
	std::queue<vertex_t> q;
	q.push(root);
	vis[root] = true;
	while(!q.empty()){
		const auto u = q.front();
		q.pop();
		for(const auto& e : g[u]){
			const auto v = e.to;
			if(vis[v]){ continue; }
			func(u, e);
			vis[v] = true;
			q.push(v);
		}
	}
}
template <typename EdgeType, typename F>
void breadth_first_search(
	const adjacency_list<EdgeType>& g,
	vertex_t root,
	F func)
{
	std::vector<bool> vis(g.size());
	breadth_first_search(g, root, vis, func);
}
}
namespace loquat {
template <typename EdgeType>
std::vector<size_t> compute_subtree_sizes(
	const adjacency_list<EdgeType>& g,
	vertex_t root)
{
	const size_t n = g.size();
	std::vector<vertex_t> order;
	order.reserve(n);
	order.push_back(root);
	breadth_first_search(g, root, [&order](vertex_t, const EdgeType& e){
		order.push_back(e.to);
	});
	std::vector<size_t> result(n);
	std::reverse(order.begin(), order.end());
	for(const auto u : order){
		size_t sum = 1;
		for(const auto& e : g[u]){
			sum += result[e.to];
		}
		result[u] = sum;
	}
	return result;
}
}
namespace loquat {
class heavy_light_decomposition {
public:
	using index_type = size_t;
	struct segment {
		index_type path_id;
		index_type first;
		index_type last;
		segment(index_type p, index_type f, index_type l)
			: path_id(p), first(f), last(l)
		{ }
	};
private:
	struct path {
		vertex_t parent;
		size_t rank;
		std::vector<vertex_t> vertices;
	};
	std::vector<path> m_paths;
	std::vector<index_type> m_vertex2path;
	std::vector<index_type> m_vertex2index;
public:
	template <typename EdgeType>
	explicit heavy_light_decomposition(
		const adjacency_list<EdgeType>& graph,
		vertex_t root = 0)
		: m_paths()
		, m_vertex2path(graph.size())
		, m_vertex2index(graph.size())
	{
		struct frame_type {
			vertex_t u;
			vertex_t p;
			frame_type() : u(0), p(0) { }
			frame_type(vertex_t u, vertex_t p) : u(u), p(p) { }
		};
		const vertex_t nil = std::numeric_limits<vertex_t>::max();
		const auto subtree_sizes = compute_subtree_sizes(graph, root);
		std::stack<frame_type> frame_stack;
		frame_stack.emplace(root, nil);
		while(!frame_stack.empty()){
			const auto f = frame_stack.top();
			frame_stack.pop();
			const index_type path_id = m_paths.size();
			path p;
			p.parent = f.p;
			p.rank = (f.p != nil ? m_paths[m_vertex2path[f.p]].rank + 1 : 0);
			vertex_t cur = f.u;
			while(cur != nil){
				const auto ss = subtree_sizes[cur];
				const auto threshold = ss / 2;
				m_vertex2path[cur] = path_id;
				m_vertex2index[cur] = p.vertices.size();
				p.vertices.push_back(cur);
				vertex_t heavy_edge = nil;
				for(const auto& e : graph[cur]){
					const auto v = e.to;
					if(subtree_sizes[v] > subtree_sizes[cur]){ continue; }
					if(heavy_edge == nil && subtree_sizes[v] >= threshold){
						heavy_edge = v;
					}else{
						frame_stack.emplace(v, cur);
					}
				}
				cur = heavy_edge;
			}
			m_paths.push_back(p);
		}
	}
	size_t count_heavy_paths() const {
		return m_paths.size();
	}
	size_t path_length(index_type p) const {
		return m_paths[p].vertices.size();
	}
	index_type path_id(vertex_t v) const {
		return m_vertex2path[v];
	}
	index_type local_index(vertex_t v) const {
		return m_vertex2index[v];
	}
	std::vector<segment> shortest_path(vertex_t s, vertex_t t) const {
		std::vector<segment> s_segments, t_segments;
		index_type s_path = path_id(s), s_index = local_index(s);
		index_type t_path = path_id(t), t_index = local_index(t);
		while(s_path != t_path){
			const size_t s_rank = m_paths[s_path].rank;
			const size_t t_rank = m_paths[t_path].rank;
			if(s_rank >= t_rank){
				const auto parent = m_paths[s_path].parent;
				s_segments.push_back(segment(s_path, s_index, 0));
				s_path  = path_id(parent);
				s_index = local_index(parent);
			}
			if(t_rank >= s_rank){
				const auto parent = m_paths[t_path].parent;
				t_segments.push_back(segment(t_path, 0, t_index));
				t_path  = path_id(parent);
				t_index = local_index(parent);
			}
		}
		std::vector<segment> result(s_segments);
		result.emplace_back(s_path, s_index, t_index);
		std::reverse(t_segments.begin(), t_segments.end());
		for(const auto& s : t_segments){ result.push_back(s); }
		return result;
	}
};
template <typename RangeQueryable>
class lazy_vertex_path_queryable_tree {
public:
	using range_queryable_type = RangeQueryable;
	using behavior_type = typename range_queryable_type::behavior_type;
	using value_type = typename behavior_type::value_type;
	using modifier_type = typename behavior_type::modifier_type;
private:
	heavy_light_decomposition m_decomposition;
	std::vector<range_queryable_type> m_range_queryables;
	lazy_range_query_behavior_wrapper<behavior_type> m_behavior;
public:
	template <typename EdgeType>
	explicit lazy_vertex_path_queryable_tree(
		const adjacency_list<EdgeType>& graph,
		vertex_t root = 0,
		const behavior_type& behavior = behavior_type())
		: m_decomposition(graph, root)
		, m_range_queryables()
		, m_behavior(behavior)
	{
		const size_t n_paths = m_decomposition.count_heavy_paths();
		m_range_queryables.reserve(n_paths);
		for(size_t i = 0; i < n_paths; ++i){
			m_range_queryables.emplace_back(
				m_decomposition.path_length(i), behavior);
		}
	}
	void modify(vertex_t s, vertex_t t, const modifier_type& m){
		const auto shortest_path = m_decomposition.shortest_path(s, t);
		modifier_type modifier = m;
		for(const auto& s : shortest_path){
			const auto path_id = s.path_id;
			const auto lo = std::min(s.first, s.last);
			const auto hi = std::max(s.first, s.last) + 1;
			const auto modifier_pair =
				m_behavior.split_modifier(modifier, hi - lo);
			const auto head_modifier = s.first > s.last
				? m_behavior.reverse_modifier(hi - lo, modifier_pair.first)
				: modifier_pair.first;
			m_range_queryables[path_id].modify(lo, hi, head_modifier);
			modifier = modifier_pair.second;
		}
	}
	value_type query(vertex_t s, vertex_t t){
		const auto shortest_path = m_decomposition.shortest_path(s, t);
		value_type acc = m_behavior.identity_value();
		for(const auto& s : shortest_path){
			const auto path_id = s.path_id;
			const auto lo = std::min(s.first, s.last);
			const auto hi = std::max(s.first, s.last) + 1;
			const auto partial = m_range_queryables[path_id].query(lo, hi);
			const auto directed_partial = s.first > s.last
				? m_behavior.reverse_value(hi - lo, partial)
				: partial;
			acc = m_behavior.merge_value(acc, directed_partial);
		}
		return acc;
	}
};
}
using namespace std;
static const int MOD = 1000000007;
using mint = loquat::modulus_integer<MOD>;
using edge = loquat::edge<>;
struct lazy_range_query_behavior {
	using value_type = mint;
	using modifier_type = pair<mint, mint>;
	value_type identity_value() const { return 0; }
	modifier_type identity_modifier() const { return make_pair(0, 0); }
	std::pair<modifier_type, modifier_type>
	split_modifier(const modifier_type& m, size_t k) const {
		return make_pair(
			modifier_type(m.first, m.second),
			modifier_type(m.first + m.second * k, m.second));
	}
	modifier_type merge_modifier(const modifier_type& a, const modifier_type& b) const {
		return modifier_type(a.first + b.first, a.second + b.second);
	}
	value_type merge_value(const value_type& a, const value_type& b) const {
		return a + b;
	}
	value_type modify(size_t n, const value_type& v, const modifier_type& m) const {
		return v + m.first * n + m.second * (n * (n - 1) / 2);
	}
	modifier_type reverse_modifier(size_t n, const modifier_type& m) const {
		return modifier_type(m.first + m.second * (n - 1), -m.second);
	}
};
using lazy_segment_tree = loquat::lazy_segment_tree<lazy_range_query_behavior>;
int main(){
	ios_base::sync_with_stdio(false);
	int n, q;
	cin >> n >> q;
	loquat::adjacency_list<edge> g(n);
	for(int i = 1; i < n; ++i){
		int a, b;
		cin >> a >> b;
		g.add_edge(a, b);
		g.add_edge(b, a);
	}
	loquat::lazy_vertex_path_queryable_tree<lazy_segment_tree> lqt(g);
	while(q--){
		int type;
		cin >> type;
		if(type == 0){
			int s, t;
			cin >> s >> t;
			cout << lqt.query(s, t) << endl;
		}else{
			int s, t, k, m;
			cin >> s >> t >> k >> m;
			lqt.modify(s, t, make_pair(k, m));
		}
	}
	return 0;
}
accuracy: 1
time_ms: 350
memory_kb: 29344
final_rank: 1

code_snippet: #include <limits>
#include <string>
#include <vector>
#include <iostream>
#include <queue>
#include <iterator>
#include <cstdint>
#include <algorithm>
#include <stack>
#include <type_traits>
#include <cstddef>
#include <utility>
namespace loquat {
namespace bitmanip {
template <typename T>
inline auto clz(T x) noexcept ->
	typename std::enable_if<sizeof(int) < sizeof(T), unsigned int>::type
{
	return __builtin_clzll(x);
}
template <typename T>
inline T clp2(T x) noexcept {
	if(x == 0u){ return 0u; }
	return T(1u) << (sizeof(T) * 8u - clz(x - 1));
}
}
}
namespace loquat {
template <typename Impl>
class lazy_range_query_behavior_wrapper {
public:
	using value_type = typename Impl::value_type;
	using modifier_type = typename Impl::modifier_type;
private:
	template <typename T>
	struct no_reverse_value {
	private:
		static std::true_type check_unary(...);
		static std::true_type check_binary(...);
	public:
		static const bool value =
			decltype(check_unary(std::declval<T>()))::value &&
			decltype(check_binary(std::declval<T>()))::value;
	};
	Impl m_impl;
	template <typename T>
	static auto split_modifier_helper(
		const T& impl, const modifier_type& m, size_t k)
		-> decltype(impl.split_modifier(m, k))
	{
		return impl.split_modifier(m, k);
	}
	template <typename T>
	static auto modify_helper(
		const T& impl, size_t n, const value_type& v, const modifier_type& m)
		-> decltype(impl.modify(n, v, m))
	{
		return impl.modify(n, v, m);
	}
	template <typename T>
	static auto reverse_value_helper(const T&, size_t, const value_type& x)
		-> typename std::enable_if<no_reverse_value<T>::value, value_type>::type
	{
		return x;
	}
	template <typename T>
	static auto reverse_modifier_helper(const T& impl, size_t n, const modifier_type& m)
		-> decltype(impl.reverse_modifier(n, m))
	{
		return impl.reverse_modifier(n, m);
	}
public:
	lazy_range_query_behavior_wrapper(Impl impl) : m_impl(std::move(impl)) { }
	value_type identity_value() const {
		return m_impl.identity_value();
	}
	modifier_type identity_modifier() const {
		return m_impl.identity_modifier();
	}
	std::pair<modifier_type, modifier_type>
	split_modifier(const modifier_type& m, size_t k) const {
		return split_modifier_helper(m_impl, m, k);
	}
	modifier_type merge_modifier(
		const modifier_type& a, const modifier_type& b) const
	{
		return m_impl.merge_modifier(a, b);
	}
	value_type merge_value(
		const value_type& a, const value_type& b) const
	{
		return m_impl.merge_value(a, b);
	}
	value_type modify(size_t n, const value_type& v, const modifier_type& m) const {
		return modify_helper(m_impl, n, v, m);
	}
	value_type reverse_value(size_t n, const value_type& m) const {
		return reverse_value_helper(m_impl, n, m);
	}
	modifier_type reverse_modifier(size_t n, const modifier_type& m) const {
		return reverse_modifier_helper(m_impl, n, m);
	}
};
}
namespace loquat {
template <typename Behavior>
class lazy_segment_tree {
public:
	using behavior_type = Behavior;
	using value_type = typename behavior_type::value_type;
	using modifier_type = typename behavior_type::modifier_type;
private:
	size_t m_actual_size;
	std::vector<value_type> m_values;
	std::vector<modifier_type> m_modifiers;
	lazy_range_query_behavior_wrapper<behavior_type> m_behavior;
	void initialize(){
		const int n = m_values.size() / 2;
		for(int i = n - 1; i >= 0; --i){
			m_values[i] = m_behavior.merge_value(
				m_values[i * 2 + 1], m_values[i * 2 + 2]);
		}
	}
	value_type modify(
		size_t a, size_t b, size_t k, size_t l, size_t r,
		const modifier_type& modifier)
	{
		if(r <= a || b <= l){
			return m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		}else if(a <= l && r <= b){
			m_modifiers[k] =
				m_behavior.merge_modifier(m_modifiers[k], modifier);
			return m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		}
		const size_t c = l + (r - l) / 2;
		const size_t lk = k * 2 + 1, rk = lk + 1;
		const auto mp = m_behavior.split_modifier(m_modifiers[k], c - l);
		m_modifiers[k] = m_behavior.identity_modifier();
		modify(l, c, lk, l, c, mp.first);
		modify(c, r, rk, c, r, mp.second);
		const auto mq = (a < c)
			? m_behavior.split_modifier(modifier, c - std::max(a, l))
			: std::make_pair(m_behavior.identity_modifier(), modifier);
		const auto vl = modify(a, b, lk, l, c, mq.first);
		const auto vr = modify(a, b, rk, c, r, mq.second);
		m_values[k] = m_behavior.merge_value(vl, vr);
		return m_values[k];
	}
	value_type query(size_t a, size_t b, size_t k, size_t l, size_t r){
		if(r <= a || b <= l){
			return m_behavior.identity_value();
		}else if(a <= l && r <= b){
			return m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		}
		const size_t c = l + (r - l) / 2;
		const size_t lk = k * 2 + 1, rk = k * 2 + 2;
		const auto mp = m_behavior.split_modifier(m_modifiers[k], c - l);
		m_values[k] = m_behavior.modify(r - l, m_values[k], m_modifiers[k]);
		m_modifiers[k] = m_behavior.identity_modifier();
		modify(l, c, lk, l, c, mp.first);
		modify(c, r, rk, c, r, mp.second);
		const auto vl = query(a, b, lk, l, c);
		const auto vr = query(a, b, rk, c, r);
		return m_behavior.merge_value(vl, vr);
	}
public:
	lazy_segment_tree(
		size_t size,
		const behavior_type& behavior = behavior_type())
		: m_actual_size(size)
		, m_values(bitmanip::clp2(size) * 2 - 1, behavior.identity_value())
		, m_modifiers(m_values.size(), behavior.identity_modifier())
		, m_behavior(behavior)
	{
		initialize();
	}
	void modify(size_t left, size_t right, const modifier_type& modifier){
		const auto clp2_n = (m_values.size() + 1) / 2;
		modify(left, right, 0, 0, clp2_n, modifier);
	}
	value_type query(size_t left, size_t right){
		const auto clp2_n = (m_values.size() + 1) / 2;
		return query(left, right, 0, 0, clp2_n);
	}
};
}
namespace loquat {
using vertex_t = size_t;
}
namespace loquat {
namespace edge_param {
struct to_ {
	vertex_t to;
	explicit to_(vertex_t t = 0)
		: to(t)
	{ }
};
}
namespace detail {
template <typename T, typename... Params>
struct edge_param_wrapper : public T, edge_param_wrapper<Params...> {
};
template <typename T>
struct edge_param_wrapper<T> : public T {
	template <typename U>
	explicit edge_param_wrapper(U&& x)
		: T(std::forward<U>(x))
	{ }
};
}
template <typename... Params>
struct edge : public detail::edge_param_wrapper<edge_param::to_, Params...> {
	template <typename... Args>
	explicit edge(Args&&... args)
		: detail::edge_param_wrapper<edge_param::to_, Params...>(
			std::forward<Args>(args)...)
	{ }
};
}
namespace loquat {
template <typename EdgeType>
class adjacency_list {
public:
	using edge_type = EdgeType;
	using edge_list = std::vector<edge_type>;
private:
	std::vector<std::vector<EdgeType>> m_edges;
public:
	explicit adjacency_list(size_t n)
		: m_edges(n)
	{ }
	size_t size() const {
		return m_edges.size();
	}
	const edge_list& operator[](vertex_t u) const {
		return m_edges[u];
	}
	template <typename... Args>
	void add_edge(vertex_t from, Args&&... args){
		m_edges[from].emplace_back(std::forward<Args>(args)...);
	}
};
}
namespace loquat {
template <typename EdgeType, typename F>
void breadth_first_search(
	const adjacency_list<EdgeType>& g,
	vertex_t root,
	std::vector<bool>& vis,
	F func)
{
	std::queue<vertex_t> q;
	q.push(root);
	vis[root] = true;
	while(!q.empty()){
		const auto u = q.front();
		q.pop();
		for(const auto& e : g[u]){
			const auto v = e.to;
			if(vis[v]){ continue; }
			func(u, e);
			vis[v] = true;
			q.push(v);
		}
	}
}
template <typename EdgeType, typename F>
void breadth_first_search(
	const adjacency_list<EdgeType>& g,
	vertex_t root,
	F func)
{
	std::vector<bool> vis(g.size());
	breadth_first_search(g, root, vis, func);
}
}
namespace loquat {
template <typename EdgeType>
std::vector<size_t> compute_subtree_sizes(
	const adjacency_list<EdgeType>& g,
	vertex_t root)
{
	const size_t n = g.size();
	std::vector<vertex_t> order;
	order.reserve(n);
	order.push_back(root);
	breadth_first_search(g, root, [&order](vertex_t, const EdgeType& e){
		order.push_back(e.to);
	});
	std::vector<size_t> result(n);
	std::reverse(order.begin(), order.end());
	for(const auto u : order){
		size_t sum = 1;
		for(const auto& e : g[u]){
			sum += result[e.to];
		}
		result[u] = sum;
	}
	return result;
}
}
namespace loquat {
class heavy_light_decomposition {
public:
	using index_type = size_t;
	struct segment {
		index_type path_id;
		index_type first;
		index_type last;
		segment(index_type p, index_type f, index_type l)
			: path_id(p), first(f), last(l)
		{ }
	};
private:
	struct path {
		vertex_t parent;
		size_t rank;
		std::vector<vertex_t> vertices;
	};
	std::vector<path> m_paths;
	std::vector<index_type> m_vertex2path;
	std::vector<index_type> m_vertex2index;
public:
	template <typename EdgeType>
	explicit heavy_light_decomposition(
		const adjacency_list<EdgeType>& graph,
		vertex_t root = 0)
		: m_paths()
		, m_vertex2path(graph.size())
		, m_vertex2index(graph.size())
	{
		struct frame_type {
			vertex_t u;
			vertex_t p;
			frame_type() : u(0), p(0) { }
			frame_type(vertex_t u, vertex_t p) : u(u), p(p) { }
		};
		const vertex_t nil = std::numeric_limits<vertex_t>::max();
		const auto subtree_sizes = compute_subtree_sizes(graph, root);
		std::stack<frame_type> frame_stack;
		frame_stack.emplace(root, nil);
		while(!frame_stack.empty()){
			const auto f = frame_stack.top();
			frame_stack.pop();
			const index_type path_id = m_paths.size();
			path p;
			p.parent = f.p;
			p.rank = (f.p != nil ? m_paths[m_vertex2path[f.p]].rank + 1 : 0);
			vertex_t cur = f.u;
			while(cur != nil){
				const auto ss = subtree_sizes[cur];
				const auto threshold = ss / 2;
				m_vertex2path[cur] = path_id;
				m_vertex2index[cur] = p.vertices.size();
				p.vertices.push_back(cur);
				vertex_t heavy_edge = nil;
				for(const auto& e : graph[cur]){
					const auto v = e.to;
					if(subtree_sizes[v] > subtree_sizes[cur]){ continue; }
					if(heavy_edge == nil && subtree_sizes[v] >= threshold){
						heavy_edge = v;
					}else{
						frame_stack.emplace(v, cur);
					}
				}
				cur = heavy_edge;
			}
			m_paths.push_back(p);
		}
	}
	size_t count_heavy_paths() const {
		return m_paths.size();
	}
	size_t path_length(index_type p) const {
		return m_paths[p].vertices.size();
	}
	index_type path_id(vertex_t v) const {
		return m_vertex2path[v];
	}
	index_type local_index(vertex_t v) const {
		return m_vertex2index[v];
	}
	std::vector<segment> shortest_path(vertex_t s, vertex_t t) const {
		std::vector<segment> s_segments, t_segments;
		index_type s_path = path_id(s), s_index = local_index(s);
		index_type t_path = path_id(t), t_index = local_index(t);
		while(s_path != t_path){
			const size_t s_rank = m_paths[s_path].rank;
			const size_t t_rank = m_paths[t_path].rank;
			if(s_rank >= t_rank){
				const auto parent = m_paths[s_path].parent;
				s_segments.push_back(segment(s_path, s_index, 0));
				s_path  = path_id(parent);
				s_index = local_index(parent);
			}
			if(t_rank >= s_rank){
				const auto parent = m_paths[t_path].parent;
				t_segments.push_back(segment(t_path, 0, t_index));
				t_path  = path_id(parent);
				t_index = local_index(parent);
			}
		}
		std::vector<segment> result(s_segments);
		result.emplace_back(s_path, s_index, t_index);
		std::reverse(t_segments.begin(), t_segments.end());
		for(const auto& s : t_segments){ result.push_back(s); }
		return result;
	}
};
template <typename RangeQueryable>
class lazy_vertex_path_queryable_tree {
public:
	using range_queryable_type = RangeQueryable;
	using behavior_type = typename range_queryable_type::behavior_type;
	using value_type = typename behavior_type::value_type;
	using modifier_type = typename behavior_type::modifier_type;
private:
	heavy_light_decomposition m_decomposition;
	std::vector<range_queryable_type> m_range_queryables;
	lazy_range_query_behavior_wrapper<behavior_type> m_behavior;
public:
	template <typename EdgeType>
	explicit lazy_vertex_path_queryable_tree(
		const adjacency_list<EdgeType>& graph,
		vertex_t root = 0,
		const behavior_type& behavior = behavior_type())
		: m_decomposition(graph, root)
		, m_range_queryables()
		, m_behavior(behavior)
	{
		const size_t n_paths = m_decomposition.count_heavy_paths();
		m_range_queryables.reserve(n_paths);
		for(size_t i = 0; i < n_paths; ++i){
			m_range_queryables.emplace_back(
				m_decomposition.path_length(i), behavior);
		}
	}
	void modify(vertex_t s, vertex_t t, const modifier_type& m){
		const auto shortest_path = m_decomposition.shortest_path(s, t);
		modifier_type modifier = m;
		for(const auto& s : shortest_path){
			const auto path_id = s.path_id;
			const auto lo = std::min(s.first, s.last);
			const auto hi = std::max(s.first, s.last) + 1;
			const auto modifier_pair =
				m_behavior.split_modifier(modifier, hi - lo);
			const auto head_modifier = s.first > s.last
				? m_behavior.reverse_modifier(hi - lo, modifier_pair.first)
				: modifier_pair.first;
			m_range_queryables[path_id].modify(lo, hi, head_modifier);
			modifier = modifier_pair.second;
		}
	}
	value_type query(vertex_t s, vertex_t t){
		const auto shortest_path = m_decomposition.shortest_path(s, t);
		value_type acc = m_behavior.identity_value();
		for(const auto& s : shortest_path){
			const auto path_id = s.path_id;
			const auto lo = std::min(s.first, s.last);
			const auto hi = std::max(s.first, s.last) + 1;
			const auto partial = m_range_queryables[path_id].query(lo, hi);
			const auto directed_partial = s.first > s.last
				? m_behavior.reverse_value(hi - lo, partial)
				: partial;
			acc = m_behavior.merge_value(acc, directed_partial);
		}
		return acc;
	}
};
}
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
using edge = loquat::edge<>;
struct lazy_range_query_behavior {
	using value_type = ll;
	using modifier_type = pll;
	value_type identity_value() const { return 0; }
	modifier_type identity_modifier() const { return pll(0, 0); }
	std::pair<modifier_type, modifier_type>
	split_modifier(const modifier_type& m, size_t k) const {
		return make_pair(
			modifier_type(m.first, m.second),
			modifier_type(m.first + m.second * k, m.second));
	}
	modifier_type merge_modifier(const modifier_type& a, const modifier_type& b) const {
		return modifier_type(a.first + b.first, a.second + b.second);
	}
	value_type merge_value(const value_type& a, const value_type& b) const {
		return a + b;
	}
	value_type modify(size_t n, const value_type& v, const modifier_type& m) const {
		return v + m.first * n + m.second * (n * (n - 1) / 2);
	}
	modifier_type reverse_modifier(size_t n, const modifier_type& m) const {
		return modifier_type(m.first + m.second * (n - 1), -m.second);
	}
};
using lazy_segment_tree = loquat::lazy_segment_tree<lazy_range_query_behavior>;
int main(){
	ios_base::sync_with_stdio(false);
	int n, q;
	cin >> n >> q;
	loquat::adjacency_list<edge> g(n);
	for(int i = 1; i < n; ++i){
		int a, b;
		cin >> a >> b;
		g.add_edge(a, b);
		g.add_edge(b, a);
	}
	loquat::lazy_vertex_path_queryable_tree<lazy_segment_tree> lqt(g);
	while(q--){
		int type;
		cin >> type;
		if(type == 0){
			int s, t;
			cin >> s >> t;
			cout << lqt.query(s, t) << endl;
		}else{
			int s, t, k, m;
			cin >> s >> t >> k >> m;
			lqt.modify(s, t, pll(k, m));
		}
	}
	return 0;
}
accuracy: 0.14893617021276595
time_ms: 160
memory_kb: 23320
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

// thanks KAZUMA!!

const int mod = 1e9 + 7;

template<int MOD>
struct mod_int {
	static const int Mod = MOD;
	unsigned x;
	mod_int() : x(0) { }
	mod_int(int sig) { int sigt = sig % MOD; if (sigt < 0) sigt += MOD; x = sigt; }
	mod_int(long long sig) { int sigt = sig % MOD; if (sigt < 0) sigt += MOD; x = sigt; }
	int get() const { return (int)x; }

	mod_int &operator+=(mod_int that) { if ((x += that.x) >= MOD) x -= MOD; return *this; }
	mod_int &operator-=(mod_int that) { if ((x += MOD - that.x) >= MOD) x -= MOD; return *this; }
	mod_int &operator*=(mod_int that) { x = (unsigned long long)x * that.x % MOD; return *this; }
	mod_int &operator/=(mod_int that) { return *this *= that.inverse(); }

	mod_int operator+(mod_int that) const { return mod_int(*this) += that; }
	mod_int operator-(mod_int that) const { return mod_int(*this) -= that; }
	mod_int operator*(mod_int that) const { return mod_int(*this) *= that; }
	mod_int operator/(mod_int that) const { return mod_int(*this) /= that; }

	mod_int inverse() const {
		long long a = x, b = MOD, u = 1, v = 0;
		while (b) {
			long long t = a / b;
			a -= t * b; swap(a, b);
			u -= t * v; swap(u, v);
		}
		return mod_int(u);
	}
};

using mint = mod_int<mod>;

struct RS {
	using type = mint;
	static type id() { return 0; }
	static type op(const type& l, const type & r) {
		return l + r;
	}
};

class lct_node {
	using M = RS;
	using T = typename M::type;
	using U = pair<mint, mint>;

	lct_node *l, *r, *p;
	bool rev;
	T val, all;
	int size;
	bool flag;
	U lazy;

	int pos() {
		if (p && p->l == this) return 1;
		if (p && p->r == this) return 3;
		return 0;
	}
	void update() {
		size = (l ? l->size : 0) + (r ? r->size : 0) + 1;
		all = M::op(l ? l->all : M::id(), M::op(val, r ? r->all : M::id()));
	}
	void update_lazy(const U& v) {
		if (!flag) lazy = make_pair(0, 0);
		int ls = !rev ? (l ? l->size : 0) : (r ? r->size : 0);
		val += v.first + v.second * ls;
		all += v.first * size + ((v.second * (size - 1)) * size) / 2;
		lazy = make_pair(M::op(lazy.first, v.first), M::op(lazy.second, v.second));
		flag = true;
	}
	void rev_data() {
		lazy = make_pair(lazy.first + lazy.second * (size - 1), mint(0) - lazy.second);
	}
	void push() {
		if (pos()) p->push();
		if (rev) {
			swap(l, r);
			if (l) l->rev ^= true, l->rev_data();
			if (r) r->rev ^= true, r->rev_data();
			rev = false;
		}
		if (flag) {
			if (l) l->update_lazy(lazy);
			if (r) r->update_lazy(make_pair(lazy.first + lazy.second * (l ? l->size + 1 : 1), lazy.second));
			flag = false;
		}
	}
	void rot() {
		lct_node *par = p;
		lct_node *mid;
		if (p->l == this) {
			mid = r;
			r = par;
			par->l = mid;
		}
		else {
			mid = l;
			l = par;
			par->r = mid;
		}
		if (mid) mid->p = par;
		p = par->p;
		par->p = this;
		if (p && p->l == par) p->l = this;
		if (p && p->r == par) p->r = this;
		par->update();
		update();
	}
	void splay() {
		push();
		while (pos()) {
			int st = pos() ^ p->pos();
			if (!st) p->rot(), rot();
			else if (st == 2) rot(), rot();
			else rot();
		}
	}

public:
	lct_node() : l(nullptr), r(nullptr), p(nullptr), rev(false), val(M::id()), all(M::id()), size(1), flag(false) {}
	void expose() {
		for (lct_node *x = this, *y = nullptr; x; y = x, x = x->p) x->splay(), x->r = y, x->update();
		splay();
	}
	void link(lct_node *x) {
		x->expose();
		expose();
		p = x;
	}
	void evert() {
		expose();
		rev = true;
		rev_data();
	}
	T find() {
		expose();
		return all;
	}
	void update(U v) {
		expose();
		update_lazy(v);
	}
};

const int MAX = 1e5+10;
lct_node lct[MAX];

void build(int v, int prev, const vector<vector<int>>& G) {
	for (int to : G[v]) if (to != prev) {
		lct[to].link(&lct[v]);
		build(to, v, G);
	}
}

int main()
{
	ios::sync_with_stdio(false), cin.tie(0);
	int N, Q;
	cin >> N >> Q;
	vector<vector<int>> G(N);
	for (int i = 0; i < N - 1; i++) {
		int u, v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	build(0, -1, G);
	while (Q--) {
		int com, u, v;
		cin >> com >> u >> v;
		if (com == 1) {
			int x,y;
			cin >> x>>y;
			lct[u].evert();
			lct[v].update(make_pair(mint(x), mint(y)));
		}
		else {
			lct[u].evert();
			printf("%d\n", lct[v].find().get());
		}
	}
	return 0;
}
accuracy: 1
time_ms: 490
memory_kb: 30368
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int mod = 1e9 + 7;

template<int MOD>
struct mod_int {
	static const int Mod = MOD;
	unsigned x;
	mod_int() : x(0) { }
	mod_int(int sig) { int sigt = sig % MOD; if (sigt < 0) sigt += MOD; x = sigt; }
	mod_int(long long sig) { int sigt = sig % MOD; if (sigt < 0) sigt += MOD; x = sigt; }
	int get() const { return (int)x; }

	mod_int &operator+=(mod_int that) { if ((x += that.x) >= MOD) x -= MOD; return *this; }
	mod_int &operator-=(mod_int that) { if ((x += MOD - that.x) >= MOD) x -= MOD; return *this; }
	mod_int &operator*=(mod_int that) { x = (unsigned long long)x * that.x % MOD; return *this; }
	mod_int &operator/=(mod_int that) { return *this *= that.inverse(); }

	mod_int operator+(mod_int that) const { return mod_int(*this) += that; }
	mod_int operator-(mod_int that) const { return mod_int(*this) -= that; }
	mod_int operator*(mod_int that) const { return mod_int(*this) *= that; }
	mod_int operator/(mod_int that) const { return mod_int(*this) /= that; }

	mod_int inverse() const {
		long long a = x, b = MOD, u = 1, v = 0;
		while (b) {
			long long t = a / b;
			a -= t * b; swap(a, b);
			u -= t * v; swap(u, v);
		}
		return mod_int(u);
	}
};

using mint = mod_int<mod>;

struct RS {
	using type = mint;
	static type id() { return 0; }
	static type op(const type& l, const type & r) {
		return l + r;
	}
};

class lct_node {
	using M = RS;
	using T = typename M::type;
	using U = pair<mint, mint>;

	lct_node *l, *r, *p;
	bool rev;
	T val, all;
	int size;
	bool flag;
	U lazy;

	int pos() {
		if (p && p->l == this) return 1;
		if (p && p->r == this) return 3;
		return 0;
	}
	void update() {
		size = (l ? l->size : 0) + (r ? r->size : 0) + 1;
		all = M::op(l ? l->all : M::id(), M::op(val, r ? r->all : M::id()));
	}
	void update_lazy(const U& v) {
		if (!flag) lazy = make_pair(0, 0);
		int ls = !rev ? (l ? l->size : 0) : (r ? r->size : 0);
		val += v.first + v.second * ls;
		all += v.first * size + ((v.second * (size - 1)) * size) / 2;
		lazy = make_pair(M::op(lazy.first, v.first), M::op(lazy.second, v.second));
		flag = true;
	}
	void rev_data() {
		lazy = make_pair(lazy.first + lazy.second * (size - 1), mint(0) - lazy.second);
	}
	void push() {
		if (pos()) p->push();
		if (rev) {
			swap(l, r);
			if (l) l->rev ^= true, l->rev_data();
			if (r) r->rev ^= true, r->rev_data();
			rev = false;
		}
		if (flag) {
			if (l) l->update_lazy(lazy);
			if (r) r->update_lazy(make_pair(lazy.first + lazy.second * (l ? l->size + 1 : 1), lazy.second));
			flag = false;
		}
	}
	void rot() {
		lct_node *par = p;
		lct_node *mid;
		if (p->l == this) {
			mid = r;
			r = par;
			par->l = mid;
		}
		else {
			mid = l;
			l = par;
			par->r = mid;
		}
		if (mid) mid->p = par;
		p = par->p;
		par->p = this;
		if (p && p->l == par) p->l = this;
		if (p && p->r == par) p->r = this;
		par->update();
		update();
	}
	void splay() {
		push();
		while (pos()) {
			int st = pos() ^ p->pos();
			if (!st) p->rot(), rot();
			else if (st == 2) rot(), rot();
			else rot();
		}
	}

public:
	lct_node() : l(nullptr), r(nullptr), p(nullptr), rev(false), val(M::id()), all(M::id()), size(1), flag(false) {}
	void expose() {
		for (lct_node *x = this, *y = nullptr; x; y = x, x = x->p) x->splay(), x->r = y, x->update();
		splay();
	}
	void link(lct_node *x) {
		x->expose();
		expose();
		p = x;
	}
	void evert() {
		expose();
		rev = true;
		rev_data();
	}
	T find() {
		expose();
		return all;
	}
	void update(U v) {
		expose();
		update_lazy(v);
	}
};

const int MAX = 1e5;
lct_node lct[MAX];

void build(int v, int prev, const vector<vector<int>>& G) {
	for (int to : G[v]) if (to != prev) {
		lct[to].link(&lct[v]);
		build(to, v, G);
	}
}

int main()
{
	ios::sync_with_stdio(false), cin.tie(0);
	int N, Q;
	cin >> N >> Q;
	vector<vector<int>> G(N);
	for (int i = 0; i < N - 1; i++) {
		int u, v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	build(0, -1, G);
	while (Q--) {
		int com, u, v;
		cin >> com >> u >> v;
		if (com == 1) {
			int k, m;
			cin >> k >> m;
			lct[u].evert();
			lct[v].update(make_pair(mint(k), mint(m)));
		}
		else {
			lct[u].evert();
			printf("%d\n", lct[v].find().get());
		}
	}
	return 0;
}
accuracy: 1
time_ms: 560
memory_kb: 30500
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;


template<typename T,typename E,typename F,typename G,typename H>
struct LinkCutTree{
  struct Node{
    Node *l,*r,*p;
    size_t sz;// tree size (only for root)
    Int idx;
    bool rev;
    T val,dat;
    E laz;
    Node():sz(1){}
    Node(Int idx,T val,E laz):
      sz(1),idx(idx),rev(0),val(val),dat(val),laz(laz){l=r=p=nullptr;}
    bool is_root(){
      return !p||(p->l!=this&&p->r!=this);
    }
  };
  
  //using F = function<T(T,T)>;
  //using G = function<T(T,E)>;
  //using H = function<E(E,E)>;
  using S = function<T(T)>;
  F f;
  G g;
  H h;
  S s;
  T ti;
  E ei;
  
  const size_t LIM = 1e6;
  vector<Node> pool;
  size_t ptr;
  
  
  LinkCutTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei),pool(LIM),ptr(0){
    s=[](T a){return a;};
  }
  
  LinkCutTree(F f,G g,H h,S s,T ti,E ei):
    f(f),g(g),h(h),s(s),ti(ti),ei(ei),pool(LIM),ptr(0){}
  
  inline Node* create(){
    return &pool[ptr++];
  }
  
  inline Node* create(Int idx,T v){
    return &(pool[ptr++]=Node(idx,v,ei));
  }

  void propagate(Node *t,E v){
    t->laz=h(t->laz,v);
    t->val=g(t->val,v);
    t->dat=g(t->dat,v);
  }

  void toggle(Node *t){
    swap(t->l,t->r);
    t->dat=s(t->dat);
    t->rev^=1;
  }

  void eval(Node *t){
    if(t->laz!=ei){
      if(t->l) propagate(t->l,t->laz);
      if(t->r) propagate(t->r,t->laz);
      t->laz=ei;
    }
    if(t->rev){
      if(t->l) toggle(t->l);
      if(t->r) toggle(t->r);
      t->rev=false;
    }
  }

  void update(Node *t){
    t->dat=t->val;
    if(t->l) t->dat=f(t->l->dat,t->dat);
    if(t->r) t->dat=f(t->dat,t->r->dat);
  }

  void rotR(Node *t){
    Node *x=t->p,*y=x->p;    
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->l=t->r)) t->r->p=x,x->sz+=x->l->sz; 
    t->r=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }
  
  void rotL(Node *t){
    Node *x=t->p,*y=x->p;
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->r=t->l)) t->l->p=x,x->sz+=x->r->sz;
    t->l=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }

  void splay(Node *t){
    eval(t);
    while(!t->is_root()){
      Node *q=t->p;
      if(q->is_root()){
	eval(q);eval(t);
	if(q->l==t) rotR(t);
	else rotL(t);
      }else{
	auto *r=q->p;
	eval(r);eval(q);eval(t);
	if(r->l==q){
	  if(q->l==t) rotR(q),rotR(t);
	  else rotL(t),rotR(t);
	}else{	
	  if(q->r==t) rotL(q),rotL(t);
	  else rotR(t),rotL(t);
	}
      }
    }
  }

  Node* expose(Node *t){
    Node *rp=nullptr;
    for(Node *c=t;c;c=c->p){
      splay(c);
      c->r=rp;
      update(c);
      rp=c;
    }
    splay(t);
    return rp;
  }

  void link(Node *par,Node *c){
    expose(c);
    expose(par);
    c->p=par;
    par->r=c;
    par->sz+=c->sz;
  }

  void cut(Node *c){
    expose(c);
    Node *par=c->l;
    c->l=nullptr;
    par->p=nullptr;
    c->sz-=par->sz;
  }

  void evert(Node *t){
    expose(t);
    toggle(t);
    eval(t);
  }

  bool is_connected(Node *a,Node *b){
    expose(a);
    while(a->l) a=a->l;
    expose(b);
    while(b->l) b=b->l;
    return a==b;
  }

  Node *lca(Node *a,Node *b){
    expose(a);
    return expose(b);
  }

  T query(Node *t){
    expose(t);
    return t->dat;
  }

  void update(Node *t,E v){
    expose(t);
    propagate(t,v);
    eval(t);
  }
};

//INSERT ABOVE HERE
signed main(){
  Int n,q;
  scanf("%lld %lld",&n,&q);
  vector<vector<Int> > G(n);
  for(Int i=1;i<n;i++){
    Int a,b;
    scanf("%lld %lld",&a,&b);
    G[a].emplace_back(b);
    G[b].emplace_back(a);
  }
  
  constexpr Int MOD = 1e9+7; 
  auto add=[](Int a,Int b){return ((a%MOD+MOD)+(b%MOD+MOD))%MOD;};
  auto mul=[](Int a,Int b){return ((a%MOD)*(b%MOD)%MOD+MOD)%MOD;};
  
  struct T{
    Int l,r,s;
    T(){}
    T(Int l,Int r,Int s):l(l),r(r),s(s){};
  };
  struct P{
    Int a,b;
    P(){}
    P(Int a,Int b):a(a),b(b){};
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  
  auto f=[&](T a,T b){return T(a.l,b.r,add(a.s,b.s));};
  auto g=[&](T a,P b){
	   Int k=a.r-a.l;
	   b.b=add(b.b,a.l*b.a)*k;
	   a.s=add(a.s,add(mul(k*(k-1)/2,b.a),b.b));
	   return a;
	 };
  auto h=[&](P a,P b){return P(add(a.a,b.a),add(a.b,b.b));};
  
  using LCT = LinkCutTree<T, P, decltype(f), decltype(g), decltype(h)>;
  LCT lct(f,g,h,T(-1,-1,0),P(0,0));
  vector<LCT::Node* > vs(n);
  
  vector<Int> ps(n,-1),dep(n,0);
  {
    queue<pair<Int, Int> > q;
    q.emplace(0,-1);
    while(!q.empty()){
      Int v,p;
      tie(v,p)=q.front();q.pop();
      vs[v]=lct.create(v,T(dep[v],dep[v]+1,0));
      ps[v]=p;
      if(~p) lct.link(vs[p],vs[v]);
      for(Int u:G[v]){
	if(u==p) continue;
	q.emplace(u,v);
	dep[u]=dep[v]+1;
      }
    }    
  }

  for(Int i=0;i<q;i++){
    Int c,s,t;
    scanf("%lld %lld %lld",&c,&s,&t);
    Int l=lct.lca(vs[s],vs[t])->idx;
    Int p=ps[l];
    
    if(c==1){
      Int b,a;
      scanf("%lld %lld",&b,&a);
      // add ax + b (different from statement)

      // [l, s] -> (p, s]
      {
	Int a1=MOD-a;
	Int b1=add(b,-a1*dep[s]);
	lct.update(vs[s],P(a1,b1));
	if(~p) lct.update(vs[p],P(-a1,-b1));
      }
      // (l, t]
      {
	Int d=dep[s]+dep[t]-2*dep[l];
	Int a2=a;
	Int b2=add(add(b,a*d),-a2*dep[t]);
	lct.update(vs[t],P(a2,b2));
	lct.update(vs[l],P(-a2,-b2));
      }
    }else{
      Int ans=0;
      // [l, s] -> (p, s]
      ans=add(ans,lct.query(vs[s]).s);
      if(~p) ans=add(ans,-lct.query(vs[p]).s);
      // (l, t]
      ans=add(ans,lct.query(vs[t]).s);
      ans=add(ans,-lct.query(vs[l]).s);
      
      printf("%lld\n",ans);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 122188
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
#define pr(...) cerr<< GET_MACRO(__VA_ARGS__,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<55)+1e9; // ~ 3.6 * 1e16
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
using T = tuple<Int,Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
template<class T1, class T2> ostream& operator<<(ostream& o,pair<T1,T2> p){return o<<"("<<p.first<<","<<p.second<<")";}
template<class T1, class T2, class T3> ostream& operator<<(ostream& o,tuple<T1,T2,T3> t){
  return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
template<class T1, class T2> istream& operator>>(istream& i,pair<T1,T2> &p){return i>>p.first>>p.second;}
template<class T> ostream& operator<<(ostream& o,vector<T> &a){Int i=0;for(T t:a)o<<(i++?" ":"")<<t;return o;}
template<class T> istream& operator>>(istream& i,vector<T> &a){for(T &t:a)i>>t;return i;}
template<class T>void prArr(T a,string s=" "){Int i=0;for(auto t:a)cout<<(i++?s:"")<<t;cout<<endl;}

class HLD{
public:
  Int V;                     //ノード数
  Int root;                  //根の頂点番号
  vector<vector<Int> > G;    //Grapth
  vector<Int> par;           //parent: par[元の頂点番号]->元の頂点番号
  vector<Int> Hchild;        //各ノードから伸びるHeavy Childの頂点番号: Hedge[元の頂点番号]->元の頂点番号
  vector<Int> number;        //各ノードに割り当てなおした頂点番号: number[元の頂点番号]->振り直した頂点番号
  vector<Int> id;            //割り当て直した数字の元のノード番号: id[振り直した頂点番号]->元の頂点番号
  vector<Int> group;         //各ノードが所属するグループ番号: group[元の頂点番号]->元の頂点番号
  vector<Int> depth;         //根からの各ノードの深さ: depth[元の頂点番号]
  bool ok;                   //build()が済んでいるか
  
  HLD(){root = V = -1;}
  HLD(Int V):V(V), root(0), G(V), par(V,-1), Hchild(V,-1), 
             number(V,-1),id(V,-1),group(V,-1),depth(V,0),ok(false){}
  
  void add_edge(Int a,Int b){
    assert(a < V && b < V);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  
  void build(Int _root = 0){
    root = _root;
    Int num = 0;
    ok = true;
    dfs1(); numbering(num); dfs2();
  }

  Int dfs1(Int pos = -1,Int pre = -1){
    if(pos == -1) pos = root;
    Int mx = -1, weight = 1;
    for(Int to:G[pos]){
      if(to == pre) continue;
      Int cweight = dfs1(to,pos);
      weight += cweight;
      if(mx < cweight) Hchild[pos] = to, mx = cweight;
    }
    return weight;
  }
  
  void dfs2(Int pos = -1,Int pre = -1,Int dep = 0,Int g = -1){
    if(pos == -1) pos = g = root;
    par[pos] = pre;
    depth[pos] = dep;
    group[pos] = g;
    for(Int to:G[pos]) if(to!=pre) dfs2(to,pos,dep+1,Hchild[pos]==to? g:to);
  }
  
  void numbering(Int &cnt,Int pos = -1,Int pre = -1){
    if(pos == -1) pos = root;
    number[pos] = cnt++;
    id[number[pos]] = pos;
    if(Hchild[pos]>=0) numbering(cnt,Hchild[pos],pos);
    for(Int to:G[pos])if(to!=pre && to!=Hchild[pos]) numbering(cnt,to,pos);
  }
  
  typedef pair<Int,Int> P;
  vector<P> paths;  //[u,v]間の経路をいくつかの「閉区間の連番の経路」に分解する。(最大logN個に分解される)
  vector<P> Ledges; //paths同士を結ぶライトエッジ
  
  //より浅い区間から追加される。つまりpaths[0].first = number[lca(u,v)];
  void buildPaths(Int u,Int v){
    if(depth[group[u]] < depth[group[v]]) swap(u,v);// 深い方のノードから処理する。
    Int nu=number[u], nv=number[v];
    if(same(u,v)){ paths.push_back(P(min(nu,nv),max(nu,nv)));return;} 

    Int gu = group[u];
    buildPaths(par[gu],v);

    paths.push_back(P(number[gu], number[u]));
    Ledges.push_back(P(number[par[gu]], number[gu]));
  }
  
  //lca(元の頂点番号,元の頂点番号) -> 元の頂点番号
  Int lca(Int u,Int v){
    assert(ok && "Please Build");
    if(depth[group[u]] < depth[group[v]]) swap(u,v);
    if(same(u,v)) return depth[u] < depth[v]? u:v;
    return lca(par[group[u]],v);
  }
  
  //getPath(元の頂点番号,元の頂点番号) -> 振り直した頂点番号
  pair<vector<P>, vector<P> > getPath(Int u,Int v){
    assert(ok && "Please Build");
    paths.clear();
    Ledges.clear();
    buildPaths(u,v);
    return make_pair(paths,Ledges);
  }

  /*(元の頂点番号,元の頂点番号)*/ 
  bool same(Int a,Int b){return group[a] == group[b];}
};

class Seg{
public: 
  typedef long long ll;

  //マージ可能な主データ型
  struct D{
    ll value;
    D():value(0){} /*適切な値にする!!!!!!*/
    D(ll value):value(value){}
  };

  //遅延用の型  
  struct T{
    Int type; //0 - empty   , 1 - update
    ll a, d;
    T():type(0), a(0), d(0){}
    T(Int type,ll a, ll d):type(type), a(a) ,d(d){}
  };

  
  Int n, n_;
  vector<D> dat;
  vector<T> td;
  HLD hld;
  D returnD = D(0); // 範囲外の時に返す値。
  
  Seg(){n=-1;}
  Seg(Int n_, HLD hld):n_(n_), hld(hld){
    n=1;
    while(n < n_) n *= 2;
    td.resize(2*n-1,T());
    dat.resize(2*n-1,D());
  }
  
  inline D merge(D a,D b){return (a.value%mod + b.value%mod+mod)%mod;}
  inline T merge(T from, T to){
    if(to.type == 0) return from;
    if(from.type == 0) return to;
    return T(1, from.a + to.a, from.d + to.d);
  }
  inline ll sum(Int l, Int r, T x){
    Int dis = hld.depth[hld.id[l]];
    Int n = r - l;
    x.a = (x.a + x.d * dis)%mod;
    return ((x.a + (x.a + x.d * (n - 1))%mod) * n / 2)%mod;
  }
  
  void delay(Int l,Int r, Int k){
    if(td[k].type==0) return;
    Int mid = (l + r) / 2;
    {
      Int i = k*2+1;
      dat[i].value = (dat[i].value + sum(l, mid, td[k]))%mod;
      td[i] = merge(td[i], td[k]);
    }

    {
      Int i = k*2+2;
      dat[i].value = (dat[i].value + sum(mid, r, td[k]))%mod;
      td[i] = merge(td[i], td[k]);
    }
    td[k] = T(0,0,0);
  }

  D write(Int l,Int r, Int k, T x){
    dat[k].value = (dat[k].value + sum(l, r, x))%mod;
    td[k] = merge(td[k], x);
    return dat[k];
  }
  
  D dfs(Int a, Int b, T x, bool flag, Int k, Int l, Int r){
    if(r <= a||b <= l) return flag? dat[k]:returnD;
    if(a <= l && r <= b) return flag? write(l, r, k, x):dat[k];
    delay(l, r, k);
    D vl = dfs(a, b, x, flag, k*2+1, l, (l+r)/2);
    D vr = dfs(a, b, x, flag, k*2+2, (l+r)/2, r);
    return flag? (dat[k] = merge(vl, vr)):merge(vl, vr);
  }

  void add(Int l,Int r,ll a, ll d){
    assert(l <= r);
    assert(0 <= l && l <= n);
    assert(0 <= r && r <= n);
    dfs(l, r, T(1, a, d), true, 0, 0, n);
  }
  
  //[l,r)の合計値を得る　find(a,b);
  ll get(Int l,Int r){
    assert(l <= r);
    assert(0 <= l && l <= n);
    assert(0 <= r && r <= n);
    D res = dfs(l, r, T(), false, 0, 0, n);
    return res.value;
  }
};


signed main(){
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  Int N, Q;
  scanf("%lld %lld", &N, &Q);
  HLD hld(N);
  for(Int i=0;i<N-1;i++){
    Int a, b;
    scanf("%lld %lld", &a, &b);
    hld.add_edge(a, b);
  }
  hld.build();
  Seg seg(N, hld);

  auto query0 = [&](Int S,Int T){
    auto path = hld.getPath(S, T).first;
    Int res = 0;
    for(auto p:path){
      Int l, r; tie(l, r) = p;
      res = (res + seg.get(l, r+1)) % mod;
    }
    return res;
  };
  
  auto query1 = [&](Int S, Int T, Int a, Int d){
    auto add = [&hld,&seg](Int s, Int t, Int a,Int d){
      auto path = hld.getPath(s, t).first;
      for(auto p:path){
	Int l,r; tie(l, r) = p;
	seg.add(l, r+1, a, d);
      }
    };
    
    Int lca = hld.lca(S, T);
    Int val = a + d * (hld.depth[S] - hld.depth[lca]);
    {
      Int na = d * hld.depth[lca] + val;
      Int nd = -d;
      add(lca, S, na, nd);
    }
    {
      Int na = -d * hld.depth[lca] + val;
      Int nd = d;
      add(lca, T, na, nd);
    }
    {
      Int na = -val;
      Int nd = 0;
      add(lca, lca, na, nd);
    }
  };

  while(Q--){
    Int cmd;
    scanf("%lld", &cmd);
    if(cmd == 0){
      Int S, T;
      scanf("%lld %lld", &S, &T);
      Int ans = query0(S, T);
      cout<<ans<<endl;
    }
    else{
      Int S, T, a, d;
      scanf("%lld %lld %lld %lld", &S, &T, &a, &d);
      query1(S, T, a, d);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 73356
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;


template<typename T,typename E,typename F,typename G,typename H>
struct LinkCutTree{
  struct Node{
    Node *l,*r,*p;
    size_t sz;// tree size (only for root)
    Int idx;
    bool rev;
    T val,dat;
    E laz;
    Node():sz(1){}
    Node(Int idx,T val,E laz):
      sz(1),idx(idx),rev(0),val(val),dat(val),laz(laz){l=r=p=nullptr;}
    bool is_root(){
      return !p||(p->l!=this&&p->r!=this);
    }
  };
  
  //using F = function<T(T,T)>;
  //using G = function<T(T,E)>;
  //using H = function<E(E,E)>;
  using S = function<T(T)>;
  F f;
  G g;
  H h;
  S s;
  T ti;
  E ei;
  
  const size_t LIM = 1e6;
  vector<Node> pool;
  size_t ptr;
  
  
  LinkCutTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei),pool(LIM),ptr(0){
    s=[](T a){return a;};
  }
  
  LinkCutTree(F f,G g,H h,S s,T ti,E ei):
    f(f),g(g),h(h),s(s),ti(ti),ei(ei),pool(LIM),ptr(0){}
  
  inline Node* create(){
    return &pool[ptr++];
  }
  
  inline Node* create(Int idx,T v){
    return &(pool[ptr++]=Node(idx,v,ei));
  }

  void propagate(Node *t,E v){
    t->laz=h(t->laz,v);
    t->val=g(t->val,v);
    t->dat=g(t->dat,v);
  }

  void toggle(Node *t){
    swap(t->l,t->r);
    t->dat=s(t->dat);
    t->rev^=1;
  }

  void eval(Node *t){
    if(t->laz!=ei){
      if(t->l) propagate(t->l,t->laz);
      if(t->r) propagate(t->r,t->laz);
      t->laz=ei;
    }
    if(t->rev){
      if(t->l) toggle(t->l);
      if(t->r) toggle(t->r);
      t->rev=false;
    }
  }

  void update(Node *t){
    t->dat=t->val;
    if(t->l) t->dat=f(t->l->dat,t->dat);
    if(t->r) t->dat=f(t->dat,t->r->dat);
  }

  void rotR(Node *t){
    Node *x=t->p,*y=x->p;    
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->l=t->r)) t->r->p=x,x->sz+=x->l->sz; 
    t->r=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }
  
  void rotL(Node *t){
    Node *x=t->p,*y=x->p;
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->r=t->l)) t->l->p=x,x->sz+=x->r->sz;
    t->l=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }

  void splay(Node *t){
    eval(t);
    while(!t->is_root()){
      Node *q=t->p;
      if(q->is_root()){
	eval(q);eval(t);
	if(q->l==t) rotR(t);
	else rotL(t);
      }else{
	auto *r=q->p;
	eval(r);eval(q);eval(t);
	if(r->l==q){
	  if(q->l==t) rotR(q),rotR(t);
	  else rotL(t),rotR(t);
	}else{	
	  if(q->r==t) rotL(q),rotL(t);
	  else rotR(t),rotL(t);
	}
      }
    }
  }

  Node* expose(Node *t){
    Node *rp=nullptr;
    for(Node *c=t;c;c=c->p){
      splay(c);
      c->r=rp;
      update(c);
      rp=c;
    }
    splay(t);
    return rp;
  }

  void link(Node *par,Node *c){
    expose(c);
    expose(par);
    c->p=par;
    par->r=c;
    par->sz+=c->sz;
  }

  void cut(Node *c){
    expose(c);
    Node *par=c->l;
    c->l=nullptr;
    par->p=nullptr;
    c->sz-=par->sz;
  }

  void evert(Node *t){
    expose(t);
    toggle(t);
    eval(t);
  }

  bool is_connected(Node *a,Node *b){
    expose(a);
    while(a->l) a=a->l;
    expose(b);
    while(b->l) b=b->l;
    return a==b;
  }

  Node *lca(Node *a,Node *b){
    expose(a);
    return expose(b);
  }

  T query(Node *t){
    expose(t);
    return t->dat;
  }

  void update(Node *t,E v){
    expose(t);
    propagate(t,v);
    eval(t);
  }
};

//INSERT ABOVE HERE
const Int MOD = 1e9+7;
signed main(){
  Int n,q;
  scanf("%lld %lld",&n,&q);
  vector<vector<Int> > G(n);
  for(Int i=1;i<n;i++){
    Int a,b;
    scanf("%lld %lld",&a,&b);
    G[a].emplace_back(b);
    G[b].emplace_back(a);
  }
  
  auto add=[](Int a,Int b){return ((a%MOD+MOD)+(b%MOD+MOD))%MOD;};
  auto mul=[](Int a,Int b){return ((a%MOD)*(b%MOD)%MOD+MOD)%MOD;};
  
  struct T{
    Int l,r,s;
    T(){}
    T(Int l,Int r,Int s):l(l),r(r),s(s){};
  };
  struct P{
    Int a,b;
    P(){}
    P(Int a,Int b):a(a),b(b){};
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  
  auto f=[&](T a,T b){return T(a.l,b.r,add(a.s,b.s));};
  auto g=[&](T a,P b){
	   Int k=a.r-a.l;
	   b.b=add(b.b,a.l*b.a)*k;
	   a.s=add(a.s,add(mul(k*(k-1)/2,b.a),b.b));
	   return a;
	 };
  auto h=[&](P a,P b){return P(add(a.a,b.a),add(a.b,b.b));};
  
  using LCT = LinkCutTree<T, P, decltype(f), decltype(g), decltype(h)>;
  LCT lct(f,g,h,T(-1,-1,0),P(0,0));
  vector<LCT::Node* > vs(n);
  
  vector<Int> ps(n,-1),dep(n,0);
  {
    queue<pair<Int, Int> > q;
    q.emplace(0,-1);
    while(!q.empty()){
      Int v,p;
      tie(v,p)=q.front();q.pop();
      vs[v]=lct.create(v,T(dep[v],dep[v]+1,0));
      ps[v]=p;
      if(~p) lct.link(vs[p],vs[v]);
      for(Int u:G[v]){
	if(u==p) continue;
	q.emplace(u,v);
	dep[u]=dep[v]+1;
      }
    }    
  }

  for(Int i=0;i<q;i++){
    Int c,s,t;
    scanf("%lld %lld %lld",&c,&s,&t);
    Int l=lct.lca(vs[s],vs[t])->idx;
    Int p=ps[l];
    
    if(c==1){
      Int b,a;
      scanf("%lld %lld",&b,&a);
      // add ax + b (different from statement)

      // [l, s] -> (p, s]
      {
	Int a1=MOD-a;
	Int b1=add(b,-a1*dep[s]);
	lct.update(vs[s],P(a1,b1));
	if(~p) lct.update(vs[p],P(-a1,-b1));
      }
      // (l, t]
      {
	Int d=dep[s]+dep[t]-2*dep[l];
	Int a2=a;
	Int b2=add(add(b,a*d),-a2*dep[t]);
	lct.update(vs[t],P(a2,b2));
	lct.update(vs[l],P(-a2,-b2));
      }
    }else{
      Int ans=0;
      // [l, s] -> (p, s]
      ans=add(ans,lct.query(vs[s]).s);
      if(~p) ans=add(ans,-lct.query(vs[p]).s);
      // (l, t]
      ans=add(ans,lct.query(vs[t]).s);
      ans=add(ans,-lct.query(vs[l]).s);
      
      printf("%lld\n",ans);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 122200
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;


template<typename T,typename E,typename F,typename G,typename H>
struct LinkCutTree{
  struct Node{
    Node *l,*r,*p;
    size_t sz;// tree size (only for root)
    Int idx;
    bool rev;
    T val,dat;
    E laz;
    Node():sz(1){}
    Node(Int idx,T val,E laz):
      sz(1),idx(idx),rev(0),val(val),dat(val),laz(laz){l=r=p=nullptr;}
    bool is_root(){
      return !p||(p->l!=this&&p->r!=this);
    }
  };
  
  //using F = function<T(T,T)>;
  //using G = function<T(T,E)>;
  //using H = function<E(E,E)>;
  using S = function<T(T)>;
  F f;
  G g;
  H h;
  S s;
  T ti;
  E ei;
  
  const size_t LIM = 1e6;
  vector<Node> pool;
  size_t ptr;
  
  
  LinkCutTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei),pool(LIM),ptr(0){
    s=[](T a){return a;};
  }
  
  LinkCutTree(F f,G g,H h,S s,T ti,E ei):
    f(f),g(g),h(h),s(s),ti(ti),ei(ei),pool(LIM),ptr(0){}
  
  inline Node* create(){
    return &pool[ptr++];
  }
  
  inline Node* create(Int idx,T v){
    return &(pool[ptr++]=Node(idx,v,ei));
  }

  void propagate(Node *t,E v){
    t->laz=h(t->laz,v);
    t->val=g(t->val,v);
    t->dat=g(t->dat,v);
  }

  void toggle(Node *t){
    swap(t->l,t->r);
    t->dat=s(t->dat);
    t->rev^=1;
  }

  void eval(Node *t){
    if(t->laz!=ei){
      if(t->l) propagate(t->l,t->laz);
      if(t->r) propagate(t->r,t->laz);
      t->laz=ei;
    }
    if(t->rev){
      if(t->l) toggle(t->l);
      if(t->r) toggle(t->r);
      t->rev=false;
    }
  }

  void update(Node *t){
    t->dat=t->val;
    if(t->l) t->dat=f(t->l->dat,t->dat);
    if(t->r) t->dat=f(t->dat,t->r->dat);
  }

  void rotR(Node *t){
    Node *x=t->p,*y=x->p;    
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->l=t->r)) t->r->p=x,x->sz+=x->l->sz; 
    t->r=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }
  
  void rotL(Node *t){
    Node *x=t->p,*y=x->p;
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->r=t->l)) t->l->p=x,x->sz+=x->r->sz;
    t->l=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }

  void splay(Node *t){
    eval(t);
    while(!t->is_root()){
      Node *q=t->p;
      if(q->is_root()){
	eval(q);eval(t);
	if(q->l==t) rotR(t);
	else rotL(t);
      }else{
	auto *r=q->p;
	eval(r);eval(q);eval(t);
	if(r->l==q){
	  if(q->l==t) rotR(q),rotR(t);
	  else rotL(t),rotR(t);
	}else{	
	  if(q->r==t) rotL(q),rotL(t);
	  else rotR(t),rotL(t);
	}
      }
    }
  }

  Node* expose(Node *t){
    Node *rp=nullptr;
    for(Node *c=t;c;c=c->p){
      splay(c);
      c->r=rp;
      update(c);
      rp=c;
    }
    splay(t);
    return rp;
  }

  void link(Node *par,Node *c){
    expose(c);
    expose(par);
    c->p=par;
    par->r=c;
    par->sz+=c->sz;
  }

  void cut(Node *c){
    expose(c);
    Node *par=c->l;
    c->l=nullptr;
    par->p=nullptr;
    c->sz-=par->sz;
  }

  void evert(Node *t){
    expose(t);
    toggle(t);
    eval(t);
  }

  bool is_connected(Node *a,Node *b){
    expose(a);
    while(a->l) a=a->l;
    expose(b);
    while(b->l) b=b->l;
    return a==b;
  }

  Node *lca(Node *a,Node *b){
    expose(a);
    return expose(b);
  }

  T query(Node *t){
    expose(t);
    return t->dat;
  }

  void update(Node *t,E v){
    expose(t);
    propagate(t,v);
    eval(t);
  }
};

//INSERT ABOVE HERE
signed main(){
  Int n,q;
  scanf("%lld %lld",&n,&q);
  vector<vector<Int> > G(n);
  for(Int i=1;i<n;i++){
    Int a,b;
    scanf("%lld %lld",&a,&b);
    G[a].emplace_back(b);
    G[b].emplace_back(a);
  }
  
  const Int MOD = 1e9+7;
  auto add=[MOD](Int a,Int b){return ((a%MOD+MOD)+(b%MOD+MOD))%MOD;};
  auto mul=[MOD](Int a,Int b){return ((a%MOD)*(b%MOD)%MOD+MOD)%MOD;};
  
  struct T{
    Int l,r,s;
    T(){}
    T(Int l,Int r,Int s):l(l),r(r),s(s){};
  };
  struct P{
    Int a,b;
    P(){}
    P(Int a,Int b):a(a),b(b){};
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  
  auto f=[&](T a,T b){return T(a.l,b.r,add(a.s,b.s));};
  auto g=[&](T a,P b){
	   Int k=a.r-a.l;
	   b.b=add(b.b,a.l*b.a)*k;
	   a.s=add(a.s,add(mul(k*(k-1)/2,b.a),b.b));
	   return a;
	 };
  auto h=[&](P a,P b){return P(add(a.a,b.a),add(a.b,b.b));};
  
  using LCT = LinkCutTree<T, P, decltype(f), decltype(g), decltype(h)>;
  LCT lct(f,g,h,T(-1,-1,0),P(0,0));
  vector<LCT::Node* > vs(n);
  
  vector<Int> ps(n,-1),dep(n,0);
  {
    queue<pair<Int, Int> > q;
    q.emplace(0,-1);
    while(!q.empty()){
      Int v,p;
      tie(v,p)=q.front();q.pop();
      vs[v]=lct.create(v,T(dep[v],dep[v]+1,0));
      ps[v]=p;
      if(~p) lct.link(vs[p],vs[v]);
      for(Int u:G[v]){
	if(u==p) continue;
	q.emplace(u,v);
	dep[u]=dep[v]+1;
      }
    }    
  }

  for(Int i=0;i<q;i++){
    Int c,s,t;
    scanf("%lld %lld %lld",&c,&s,&t);
    Int l=lct.lca(vs[s],vs[t])->idx;
    Int p=ps[l];
    
    if(c==1){
      Int b,a;
      scanf("%lld %lld",&b,&a);
      // add ax + b (different from statement)

      // [l, s] -> (p, s]
      {
	Int a1=MOD-a;
	Int b1=add(b,-a1*dep[s]);
	lct.update(vs[s],P(a1,b1));
	if(~p) lct.update(vs[p],P(-a1,-b1));
      }
      // (l, t]
      {
	Int d=dep[s]+dep[t]-2*dep[l];
	Int a2=a;
	Int b2=add(add(b,a*d),-a2*dep[t]);
	lct.update(vs[t],P(a2,b2));
	lct.update(vs[l],P(-a2,-b2));
      }
    }else{
      Int ans=0;
      // [l, s] -> (p, s]
      ans=add(ans,lct.query(vs[s]).s);
      if(~p) ans=add(ans,-lct.query(vs[p]).s);
      // (l, t]
      ans=add(ans,lct.query(vs[t]).s);
      ans=add(ans,-lct.query(vs[l]).s);
      
      printf("%lld\n",ans);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 3130
memory_kb: 122132
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;

struct HLDecomposition {
  Int n,pos;
  vector<vector<Int> > G;
  vector<Int> vid, head, sub, hvy, par, dep, inv, type;
  
  HLDecomposition(){}
  HLDecomposition(Int sz):
    n(sz),pos(0),G(n),
    vid(n,-1),head(n),sub(n,1),hvy(n,-1),
    par(n),dep(n),inv(n),type(n){}
  
  void add_edge(Int u, Int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }

  void build(vector<Int> rs={0}) {
    Int c=0;
    for(Int r:rs){
      dfs(r);
      bfs(r, c++);
    }
  }
  
  void dfs(Int rt) {
    using T = pair<Int, Int>;
    stack<T> st;
    par[rt]=-1;
    dep[rt]=0;
    st.emplace(rt,0);
    while(!st.empty()){
      Int v=st.top().first;
      Int &i=st.top().second;
      if(i<(Int)G[v].size()){
	Int u=G[v][i++];
	if(u==par[v]) continue;
	par[u]=v;
	dep[u]=dep[v]+1;
	st.emplace(u,0);
      }else{
	st.pop();
	for(Int j=0;j<(Int)G[v].size();j++){
	  Int &u=G[v][j];
	  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 bfs(Int r,Int c) {
    using T = tuple<Int, Int, Int>;
    stack<T> st;
    st.emplace(r,r,0);
    while(!st.empty()){
      Int v,h;
      tie(v,h,ignore)=st.top();
      Int &i=get<2>(st.top());
      if(!i){
	type[v]=c;
	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<(Int)G[v].size()){
	Int u=G[v][i++];
	if(u==par[v]) continue;
	st.emplace(u,(hvy[v]==u?h:u),0);
      }else{
	st.pop();
      }
    }
  }
  
  // for_each(vertex)
  // [l,r] <- attention!!  
  template<typename F>
  void for_each(Int u, Int v, const F& 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;
    }
  }

  template<typename T,typename Q,typename F>
  T for_each(Int u,Int v,T ti,const Q &q,const F &f){
    T l=ti,r=ti;
    while(1){
      if(vid[u]>vid[v]){
	swap(u,v);
	swap(l,r);
      }
      l=f(l,q(max(vid[head[v]],vid[u]),vid[v]));
      if(head[u]!=head[v]) v=par[head[v]];
      else break;
    }
    return f(l,r);
  }
  
  // for_each(edge)
  // [l,r] <- attention!!
  template<typename F>
  void for_each_edge(Int u, Int v,const F& 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;
      }
    }
  }

  Int lca(Int u,Int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v=par[head[v]];
    }
  }

  Int distance(Int u,Int v){
    return dep[u]+dep[v]-2*dep[lca(u,v)];
  }
};


template <typename T,typename E>
struct SegmentTree{
  using F = function<T(T,T)>;
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  Int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  SegmentTree(Int n_,F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){init(n_);}
  void init(Int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
  }
  void build(Int n_, vector<T> v){
    for(Int i=0;i<n_;i++) dat[n+i]=v[i];
    for(Int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  T reflect(Int k){
    return g(dat[k],laz[k]);
  }
  inline void eval(Int k){
    if(laz[k]==ei) return;
    laz[(k<<1)|0]=h(laz[(k<<1)|0],laz[k]);
    laz[(k<<1)|1]=h(laz[(k<<1)|1],laz[k]);
    dat[k]=reflect(k);
    laz[k]=ei;
  }
  void update(Int a,Int b,E x){
    a+=n;b+=n-1;
    for(Int i=height;i;i--) eval(a>>i);
    for(Int i=height;i;i--) eval(b>>i);
    for(Int l=a,r=b+1;l<r;l>>=1,r>>=1){
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    while(a>>=1)
      dat[a]=f(reflect((a<<1)|0),reflect((a<<1)|1));
    while(b>>=1)
      dat[b]=f(reflect((b<<1)|0),reflect((b<<1)|1));
  }
  T query(Int a,Int b){
    a+=n;b+=n-1;
    for(Int i=height;i;i--) eval(a>>i);
    for(Int i=height;i;i--) eval(b>>i);
    T vl=ti,vr=ti;
    for(Int l=a,r=b+1;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,reflect(l++));
      if(r&1) vr=f(reflect(--r),vr);
    }
    return f(vl,vr);
  }
};

//INSERT ABOVE HERE
signed main(){
  Int n,q;
  scanf("%lld %lld",&n,&q);
  
  HLDecomposition hld(n);
  for(Int i=1;i<n;i++){
    Int a,b;
    scanf("%lld %lld",&a,&b);
    hld.add_edge(a,b);
  }
  hld.build();
  
  const Int MOD = 1e9+7;
  using T = tuple<Int, Int, Int>;
  using P = pair<Int, Int>;
  auto f=[](T a,T b){
	   Int al,ar,as,bl,br,bs;
	   tie(al,ar,as)=a;
	   tie(bl,br,bs)=b;
	   return T(al,br,(as+bs)%MOD);
	 };
  auto g=[](T a,P b){
	   Int al,ar,as,ba,bb;
	   tie(al,ar,as)=a;
	   tie(ba,bb)=b;
	   bb+=al*ba%MOD;
	   Int k=ar-al;
	   as+=(k*(k-1)/2%MOD*ba%MOD)+(bb*k%MOD);
	   return T(al,ar,as%MOD);
	 };
  auto h=[](P a,P b){
	   return P((a.first+b.first)%MOD,(a.second+b.second)%MOD);
	 };

  SegmentTree<T, P> seg(n,f,g,h,T(-1,-1,0),P(0,0));
  vector<T> vt(n);
  for(Int i=0;i<n;i++) vt[hld.vid[i]]=T(hld.dep[i],hld.dep[i]+1,0);
  seg.build(n,vt);
  
  for(Int i=0;i<q;i++){
    Int c,s,t;
    scanf("%lld %lld %lld",&c,&s,&t);
    Int l=hld.lca(s,t);
    
    if(c==1){
      Int b,a;
      scanf("%lld %lld",&b,&a);
      Int up=(b+MOD-hld.dep[s]*(MOD-a)%MOD)%MOD;
      Int dw=(b+hld.distance(s,t)*a%MOD+MOD-hld.dep[t]*a%MOD)%MOD;      
      hld.for_each(l,s,[&](Int l,Int r){seg.update(l,r+1,P(MOD-a,up));});
      hld.for_each_edge(l,t,[&](Int l,Int r){seg.update(l,r+1,P(a,dw));});      
    }else{      
      auto ask=[&](Int l,Int r){return seg.query(l,r+1);};
      T ans=hld.for_each(s,t,T(0,0,0),ask,f);
      printf("%lld\n",get<2>(ans));
    }
  }
  return 0;
}
accuracy: 1
time_ms: 850
memory_kb: 29620
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;


template<typename T,typename E,typename F,typename G,typename H>
struct LinkCutTree{
  struct Node{
    Node *l,*r,*p;
    size_t sz;// tree size (only for root)
    Int idx;
    bool rev;
    T val,dat;
    E laz;
    Node():sz(1){}
    Node(Int idx,T val,E laz):
      sz(1),idx(idx),rev(0),val(val),dat(val),laz(laz){l=r=p=nullptr;}
    bool is_root(){
      return !p||(p->l!=this&&p->r!=this);
    }
  };
  
  //using F = function<T(T,T)>;
  //using G = function<T(T,E)>;
  //using H = function<E(E,E)>;
  using S = function<T(T)>;
  F f;
  G g;
  H h;
  S s;
  T ti;
  E ei;
  
  const size_t LIM = 1e6;
  vector<Node> pool;
  size_t ptr;
  
  
  LinkCutTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei),pool(LIM),ptr(0){
    s=[](T a){return a;};
  }
  
  LinkCutTree(F f,G g,H h,S s,T ti,E ei):
    f(f),g(g),h(h),s(s),ti(ti),ei(ei),pool(LIM),ptr(0){}
  
  inline Node* create(){
    return &pool[ptr++];
  }
  
  inline Node* create(Int idx,T v){
    return &(pool[ptr++]=Node(idx,v,ei));
  }

  void propagate(Node *t,E v){
    t->laz=h(t->laz,v);
    t->val=g(t->val,v);
    t->dat=g(t->dat,v);
  }

  void toggle(Node *t){
    swap(t->l,t->r);
    t->dat=s(t->dat);
    t->rev^=1;
  }

  void eval(Node *t){
    if(t->laz!=ei){
      if(t->l) propagate(t->l,t->laz);
      if(t->r) propagate(t->r,t->laz);
      t->laz=ei;
    }
    if(t->rev){
      if(t->l) toggle(t->l);
      if(t->r) toggle(t->r);
      t->rev=false;
    }
  }

  void update(Node *t){
    t->dat=t->val;
    if(t->l) t->dat=f(t->l->dat,t->dat);
    if(t->r) t->dat=f(t->dat,t->r->dat);
  }

  void rotR(Node *t){
    Node *x=t->p,*y=x->p;    
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->l=t->r)) t->r->p=x,x->sz+=x->l->sz; 
    t->r=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }
  
  void rotL(Node *t){
    Node *x=t->p,*y=x->p;
    x->sz-=t->sz;
    t->sz+=x->sz;
    if((x->r=t->l)) t->l->p=x,x->sz+=x->r->sz;
    t->l=x;x->p=t;
    update(x);update(t);
    if((t->p=y)){
      if(y->l==x) y->l=t;
      if(y->r==x) y->r=t;
      update(y);
    }
  }

  void splay(Node *t){
    eval(t);
    while(!t->is_root()){
      Node *q=t->p;
      if(q->is_root()){
	eval(q);eval(t);
	if(q->l==t) rotR(t);
	else rotL(t);
      }else{
	auto *r=q->p;
	eval(r);eval(q);eval(t);
	if(r->l==q){
	  if(q->l==t) rotR(q),rotR(t);
	  else rotL(t),rotR(t);
	}else{	
	  if(q->r==t) rotL(q),rotL(t);
	  else rotR(t),rotL(t);
	}
      }
    }
  }

  Node* expose(Node *t){
    Node *rp=nullptr;
    for(Node *c=t;c;c=c->p){
      splay(c);
      c->r=rp;
      update(c);
      rp=c;
    }
    splay(t);
    return rp;
  }

  void link(Node *par,Node *c){
    expose(c);
    expose(par);
    c->p=par;
    par->r=c;
    par->sz+=c->sz;
  }

  void cut(Node *c){
    expose(c);
    Node *par=c->l;
    c->l=nullptr;
    par->p=nullptr;
    c->sz-=par->sz;
  }

  void evert(Node *t){
    expose(t);
    toggle(t);
    eval(t);
  }

  bool is_connected(Node *a,Node *b){
    expose(a);
    while(a->l) a=a->l;
    expose(b);
    while(b->l) b=b->l;
    return a==b;
  }

  Node *lca(Node *a,Node *b){
    expose(a);
    return expose(b);
  }

  T query(Node *t){
    expose(t);
    return t->dat;
  }

  void update(Node *t,E v){
    expose(t);
    propagate(t,v);
    eval(t);
  }
};

//INSERT ABOVE HERE
const Int MOD = 1e9+7;
signed main(){
  Int n,q;
  scanf("%lld %lld",&n,&q);
  vector<vector<Int> > G(n);
  for(Int i=1;i<n;i++){
    Int a,b;
    scanf("%lld %lld",&a,&b);
    G[a].emplace_back(b);
    G[b].emplace_back(a);
  }
  
  auto add=[](Int a,Int b){return (a+b)%MOD;};
  auto mul=[](Int a,Int b){return (a*b)%MOD;};
  
  struct T{
    Int l,r,s;
    T(){}
    T(Int l,Int r,Int s):l(l),r(r),s(s){};
  };
  struct P{
    Int a,b;
    P(){}
    P(Int a,Int b):a(a),b(b){};
    bool operator!=(const P &x)const{return a!=x.a||b!=x.b;}
  };
  
  auto f=[&](T a,T b){return T(a.l,b.r,add(a.s,b.s));};
  auto g=[&](T a,P b){
	   Int k=a.r-a.l;
	   b.b=add(b.b,a.l*b.a)*k;
	   a.s=add(a.s,add(mul(k*(k-1)/2%MOD,b.a),b.b));
	   return a;
	 };
  auto h=[&](P a,P b){return P(add(a.a,b.a),add(a.b,b.b));};
  
  using LCT = LinkCutTree<T, P, decltype(f), decltype(g), decltype(h)>;
  LCT lct(f,g,h,T(-1,-1,0),P(0,0));
  vector<LCT::Node* > vs(n);
  
  vector<Int> ps(n,-1),dep(n,0);
  {
    queue<pair<Int, Int> > q;
    q.emplace(0,-1);
    while(!q.empty()){
      Int v,p;
      tie(v,p)=q.front();q.pop();
      vs[v]=lct.create(v,T(dep[v],dep[v]+1,0));
      ps[v]=p;
      if(~p) lct.link(vs[p],vs[v]);
      for(Int u:G[v]){
	if(u==p) continue;
	q.emplace(u,v);
	dep[u]=dep[v]+1;
      }
    }    
  }

  for(Int i=0;i<q;i++){
    Int c,s,t;
    scanf("%lld %lld %lld",&c,&s,&t);
    Int l=lct.lca(vs[s],vs[t])->idx;
    Int p=ps[l];
    
    if(c==1){
      Int b,a;
      scanf("%lld %lld",&b,&a);
      // add ax + b (different from statement)

      // [l, s] -> (p, s]
      {
	Int a1=MOD-a;
	Int b1=add(b,-a1*dep[s]);
	lct.update(vs[s],P(a1,b1));
	if(~p) lct.update(vs[p],P(-a1,-b1));
      }
      // (l, t]
      {
	Int d=dep[s]+dep[t]-2*dep[l];
	Int a2=a;
	Int b2=add(add(b,a*d),-a2*dep[t]);
	lct.update(vs[t],P(a2,b2));
	lct.update(vs[l],P(-a2,-b2));
      }
    }else{
      Int ans=0;
      // [l, s] -> (p, s]
      ans=add(ans,lct.query(vs[s]).s);
      if(~p) ans=add(ans,-lct.query(vs[p]).s);
      // (l, t]
      ans=add(ans,lct.query(vs[t]).s);
      ans=add(ans,-lct.query(vs[l]).s);

      ans%=MOD;
      ans+=MOD;
      ans%=MOD;
      printf("%lld\n",ans);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 430
memory_kb: 122188
final_rank: 11