Problem:
F : Tree / 木
問題文
大きさ
N
の根付き木がある。 各頂点には
0
から
N−1
までの番号が付けられ、根が
0
である。 任意の辺の両端の頂点について、割り当てられた整数は根に近いほうが小さい。初めは全ての辺の重みは
0
である。
この木に対する
Q
個のクエリを順に処理せよ。クエリには以下の
2
種類がある。
頂点
u
,
v
の距離(パスに含まれる辺の重みの和)を求める。
頂点
v
の子孫(自身を含まない)に接続する辺の重みを全て
x
増加させる。
入力
入力は以下の形式からなる。
N
Q
a_0
b_0
…
a_{N−2}
b_{N−2}
q_0
…
q_{Q−1}
a_i,b_i
は
i
番目の辺が結ぶ頂点である。
q_i
は
i
番目のクエリを表す
3
つの整数であり、次のうちいずれかである。
0 \ u_i \ v_i
: 頂点
u_i, v_i
の距離を求める。
1 \ v_i \ x_i
: 頂点
v_i
の子孫に接続する辺の重みを全て
x_i
増加させる。
制約
入力はすべて整数である
2 \≤ N \≤ 150\,000
1 \≤ Q \≤ 150\,000
0 \≤ a_{i},b_{i},u_{i},v_{i} \≤ N−1
a_{i} < b_{i}
0 \≤ x_{i} \≤ 300
出力
距離を求めるクエリのたびに、結果を1行で出力せよ。
注意
この問題では入出力が非常に大きくなりうるので高速な関数を使用してほしい。
サンプル
サンプル入力1
9 6
0 1
0 2
0 3
1 4
1 5
4 6
5 7
5 8
1 0 1
1 1 2
0 6 3
1 5 5
1 8 4
0 4 3
サンプル出力1
8
5
図のようになる。
サンプル入力2
13 7
0 1
1 2
2 3
1 4
3 5
1 6
2 7
0 8
7 9
5 10
8 11
1 12
1 2 143
0 8 7
0 10 6
1 1 42
1 6 37
0 3 6
1 6 38
サンプル出力2
143
429
269

Submitted solutions:

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

#define g(x) ((x)>>i)
#define f(x) (g(x)<<i) != x
#define r() for(int i = 1; i <= lg; i++)
#define rr() for(int i = lg; i >= 1; i--)
template<typename S, S(*op)(S, S), S(*e)(), typename F, S(*mapping)(F, S), F(*composition)(F, F), F(*id)()>
struct lazy_segtree {
    int n, s, lg;
    vector<S> d;
    vector<F> v;
    
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    lazy_segtree(const vector<S> &x) : n(x.size()) {
        s = 1;
        while(s < n) s <<= 1;
        lg = __builtin_ctz(s);
        d = vector<S>(2*s, e());
        v = vector<F>(s, id());
        for(int i = 0; i < n; i++) d[s+i] = x[i];
        for(int i = s-1; i >= 1; i--) b(i);
    }
    
    void b(int k) {d[k] = op(d[2*k], d[2*k+1]);}
    void c(int k, F f) {
        d[k] = mapping(f, d[k]);
        if(k < s) v[k] = composition(f, v[k]);
    }
    void push(int k) {
        c(2*k, v[k]);
        c(2*k+1, v[k]);
        v[k] = id();
    }
    
    void set(int p, S x){
        p += s;
        rr() push(g(p));
        d[p] = x;
        r() b(g(p));
    }
    
    S get(int p){
        p += s;
        rr() push(g(p));
        return d[p];
    }
    
    S prod(int l, int r){
        if(l == r) return e();
        l += s; r += s;
        rr(){
            if(f(l)) push(g(l));
            if(f(r)) push(g(r-1));
        }
        S L = e(), R = e();
        while(l < r){
            if(l&1) L = op(L, d[l++]);
            if(r&1) R = op(d[--r], R);
            l>>=1; r>>=1;
        }
        return op(L, R);
    }
    
    S all_prod() {return d[1];}
    
    void apply(int p, F f){
        p += s;
        rr() push(g(p));
        d[p] = mapping(f, d[p]);
        r() b(g(p));
    }
    void apply(int l, int r, F f){
        if(l == r) return;
        l += s; r += s;
        rr(){
            if(f(l)) push(g(l));
            if(f(r)) push(g(r-1));
        }
        {
            int l2 = l, r2 = r;
            while(l < r){
                if(l&1) c(l++, f);
                if(r&1) c(--r, f);
                l>>=1; r>>=1;
            }
            l = l2; r = r2;
        }
        r(){
            if(f(l)) b(g(l));
            if(f(r)) b(g(r-1));
        }
    }
};
#undef f
#undef g
#undef r
#undef rr

template<class S, S(*op)(S, S), S(*e)(), typename F, S(*mapping)(F, S), F(*composition)(F, F), F(*id)()>
struct hld{
    using node_type = lazy_segtree<S, op, e, F, mapping, composition, id>;
    //using node_type = segtree<S, op, e, F, mapping, composition, id>
    
    int *dum0, *dum1;
    int n, r, edge_idx;
    int *dep, *in, *out, *head, *par;
    int *E;
    S *V;
    
    node_type node[2];
    
    hld(int _n, int _r = -1):
        n(_n), r(_r), edge_idx(0){
            if(r == -1) r = random_device()()%n;
            dum0 = new int[n*7-2];
            dep = dum0;
            in = dum0+n;
            out = dum0+n*2;
            head = dum0+n*3;
            par = dum0+n*4;
            E = dum0+n*5;
            V = new S[n-1];
        }
    
    void add_edge(int u, int v, const S &x){
        V[edge_idx/2] = x;
        E[edge_idx++] = u;
        E[edge_idx++] = v;
    }
    
    void build(){
        dum1 = new int[n*8+1];
        int *g = dum1;
        int *start = dum1+n*2-2;
        int *C = dum1+n*3-1;
        S *val = new S[(n-1)*2];
        memset(start, 0, sizeof(int)*(n+1));
        
        for(int i = 0; i < 2*n-2; i+=2){
            start[E[i]+1]++;
            start[E[i+1]+1]++;
        }
        for(int i = 1; i <= n; i++) start[i] += start[i-1];
        memcpy(C, start, sizeof(int)*(n+1));
        
        for(int i = 0; i < 2*n-2; i+=2){
            val[C[E[i]]] = V[i/2];
            g[C[E[i]]++] = E[i+1];
            val[C[E[i+1]]] = V[i/2];
            g[C[E[i+1]]++] = E[i];
        }
        
        int *sub_siz = dum1+n*4;
        int *idx = dum1+n*5;
        fill(sub_siz, sub_siz+n, 1);
        memcpy(idx, start, sizeof(int)*(n+1));
        
        int cur = r;
        par[r] = -1;
        while(true){
            if(idx[cur] < start[cur+1]-(cur!=r)){
                int nex = g[idx[cur]++];
                if(nex == par[cur]){
                    --idx[cur];
                    val[idx[cur]] = val[start[cur+1]-1];
                    g[idx[cur]] = g[start[cur+1]-1];
                    continue;
                }
                par[nex] = cur;
                cur = nex;
            } else {
                if(cur == r) break;
                sub_siz[par[cur]] += sub_siz[cur];
                cur = par[cur];
            }
        }
        
        memcpy(idx, start, sizeof(int)*(n+1));
        int *state = dum1+n*6+1;
        int *heavy = dum1+n*7+1;
        memset(state, 0, sizeof(int)*n);
        
        int node_siz = 0;
        cur = r;
        head[cur] = r;
        dep[cur] = 0;
        while(1){
            if(state[cur] == 0){
                in[cur] = node_siz++;
                heavy[cur] = -1;
                for(int i = start[cur]; i < start[cur+1]-(cur!=r); i++){
                    int nex = g[i];
                    if(heavy[cur] == -1 || sub_siz[heavy[cur]] < sub_siz[nex]){
                        heavy[cur] = nex;
                    }
                }
                if(heavy[cur] != -1){
                    int nex = heavy[cur];
                    dep[nex] = dep[cur];
                    head[nex] = head[cur];
                    state[cur] = 2;
                    cur = nex;
                } else state[cur] = 2;
            } else if(state[cur] == 2){
                if(idx[cur] < start[cur+1]-(cur!=r)){
                    int nex = g[idx[cur]++];
                    if(nex == heavy[cur]) continue;
                    dep[nex] = dep[cur]+1;
                    head[nex] = nex;
                    cur = nex;
                } else state[cur] = 3;
            } else {
                out[cur] = node_siz;
                if(cur == r) break;
                cur = par[cur];
            }
        }
        
        vector<S> node_v(n);
        for(int i = 0; i < n; i++){
            for(int j = start[i]; j < start[i+1]-(i!=r); j++){
                node_v[in[g[j]]] = val[j];
            }
        }
        
        node[0] = node_type(node_v);
        reverse(node_v.begin(), node_v.end());
        node[1] = node_type(node_v);
    }
    
    void add(int u, int v, const S& x){
        if(dep[u] != dep[v]){
            if(dep[u] < dep[v]) u = v;
            node[0].add(in[u], x);
            node[1].add(in[u], x);
        } else {
            if(head[u] < head[v]) u = v;
            node[0].add(in[u], x);
            node[1].add(in[u], x);
        }
    }
    
    S prod(int l, int r){
        assert(0 <= l && 0 <= r && l < n && r < n);
        S l_ans = e();
        S r_ans = e();
        bool rev = false;
        while(true){
            if(dep[l] < dep[r]) swap(l, r), rev ^= 1;
            if(dep[l] != dep[r] || head[l] != head[r]){
                if(!rev) l_ans = op(l_ans, node[1].prod(n-in[l]-1, n-in[head[l]]));
                else r_ans = op(node[0].prod(in[head[l]], in[l]+1), r_ans);
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r), rev ^= 1;
                if(!rev) l_ans = op(l_ans, node[0].prod(in[l]+1, in[r]+1));
                else r_ans = op(node[1].prod(n-in[r]-1, n-in[l]-1), r_ans);
                return op(l_ans, r_ans);
            }
        }
    }
    
    S prod(int r){
        assert(0 <= r && r < n);
        return node[0].prod(in[r]+1, out[r]);
    }
    
    void set(int u, int v, const S& x){
        if(dep[u] != dep[v]){
            if(dep[u] < dep[v]) u = v;
            node[0].set(in[u], x);
            node[1].set(n-in[u]-1, x);
        } else {
            if(in[u] < in[v]) u = v;
            node[0].set(in[u], x);
            node[1].set(n-in[u]-1, x);
        }
    }
    
    S get(int u, int v){
        if(dep[u] != dep[v]){
            if(dep[u] < dep[v]) u = v;
            return node[0].get(in[u]);
        } else {
            if(in[u] < in[v]) u = v;
            return node[0].get(in[u]);
        }
    }
    
    int lca(int l, int r){
        assert(0 <= l && 0 <= r && l < n && r < n);
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                return l;
            }
        }
    }
    
    int dist(int l, int r){
        assert(0 <= l && 0 <= r && l < n && r < n);
        int d = 0;
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                d += in[l] - in[head[l]] + 1;
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                d += in[r] - in[l];
                return d;
            }
        }
    }
    
    void apply(int l, int r, const F& x){
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                node[0].apply(in[head[l]], in[l]+1, x);
                node[1].apply(n-in[l]-1, n-in[head[l]], x);
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                node[0].apply(in[l]+1, in[r]+1, x);
                node[1].apply(n-in[r]-1, n-in[l]-1, x);
                break;
            }
        }
    }
    
    void apply(int r, const F& x){
        node[0].apply(in[r]+1, out[r], x);
        node[1].apply(n-out[r], n-in[r]-1, x);
    }
};

using S = pair<long long, int>;
S op(S l, S r) {return {l.first+r.first, l.second+r.second};}
S e() {return {0, 0};}
using F = long long;
S mapping(F f, S x) {return {x.first + f*x.second, x.second};}
F composition(F f, F g) {return f+g;}
F id() {return 0ll;}

int main(){
    cin.tie(0)->sync_with_stdio(0);
    
    int n, q;
    cin >> n >> q;
    hld<S, op, e, F, mapping, composition, id> seg(n, 0);
    
    for(int i = 0; i < n-1; i++){
        int a, b;
        cin >> a >> b;
        seg.add_edge(a, b, {0, 1});
    }
    seg.build();
    
    while(q--){
        int t, a, b;
        cin >> t >> a >> b;
        if(t == 0) cout << seg.prod(a, b).first << '\n';
        else seg.apply(a, b);
    }
}
accuracy: 1
time_ms: 240
memory_kb: 41736
final_rank: 4

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

#define g(x) ((x)>>i)
#define f(x) (g(x)<<i) != x
#define r() for(int i = 1; i <= lg; i++)
#define rr() for(int i = lg; i >= 1; i--)
template<typename S, S(*op)(S, S), S(*e)(), typename F, S(*mapping)(F, S), F(*composition)(F, F), F(*id)()>
struct lazy_segtree {
    int n, s, lg;
    vector<S> d;
    vector<F> v;
    
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    lazy_segtree(const vector<S> &x) : n(x.size()) {
        s = 1;
        while(s < n) s <<= 1;
        lg = __builtin_ctz(s);
        d = vector<S>(2*s, e());
        v = vector<F>(s, id());
        for(int i = 0; i < n; i++) d[s+i] = x[i];
        for(int i = s-1; i >= 1; i--) b(i);
    }
    
    void b(int k) {d[k] = op(d[2*k], d[2*k+1]);}
    void c(int k, F f) {
        d[k] = mapping(f, d[k]);
        if(k < s) v[k] = composition(f, v[k]);
    }
    void push(int k) {
        c(2*k, v[k]);
        c(2*k+1, v[k]);
        v[k] = id();
    }
    
    void set(int p, S x){
        p += s;
        rr() push(g(p));
        d[p] = x;
        r() b(g(p));
    }
    
    S get(int p){
        p += s;
        rr() push(g(p));
        return d[p];
    }
    
    S prod(int l, int r){
        if(l == r) return e();
        l += s; r += s;
        rr(){
            if(f(l)) push(g(l));
            if(f(r)) push(g(r-1));
        }
        S L = e(), R = e();
        while(l < r){
            if(l&1) L = op(L, d[l++]);
            if(r&1) R = op(d[--r], R);
            l>>=1; r>>=1;
        }
        return op(L, R);
    }
    
    S all_prod() {return d[1];}
    
    void apply(int p, F f){
        p += s;
        rr() push(g(p));
        d[p] = mapping(f, d[p]);
        r() b(g(p));
    }
    void apply(int l, int r, F f){
        if(l == r) return;
        l += s; r += s;
        rr(){
            if(f(l)) push(g(l));
            if(f(r)) push(g(r-1));
        }
        {
            int l2 = l, r2 = r;
            while(l < r){
                if(l&1) c(l++, f);
                if(r&1) c(--r, f);
                l>>=1; r>>=1;
            }
            l = l2; r = r2;
        }
        r(){
            if(f(l)) b(g(l));
            if(f(r)) b(g(r-1));
        }
    }
};
#undef f
#undef g
#undef r
#undef rr

template<typename S, S(*op)(S, S), S(*e)(), typename F, S(*mapping)(F, S), F(*composition)(F, F), F(*id)()>
struct HLD {
    using seg_t = lazy_segtree<S, op, e, F, mapping, composition, id>;
    
    int n;
    vector<int> dep, in, out, head, par;
    vector<pair<array<int, 2>, S>> E;
    seg_t node[2];
    
    HLD(int _n) : n(_n), dep(n), in(n), out(n), head(n), par(n) {}
    
    void add_edge(int u, int v, const S &x){
        E.push_back({{u, v}, x});
    }
    
    void build(){
        vector<vector<pair<int, S>>> G(n);
        for(auto i : E){
            G[i.first[0]].push_back({i.first[1], i.second});
            G[i.first[1]].push_back({i.first[0], i.second});
        }
        
        vector<int> sub_siz(n, 1);
        
        par[0] = -1;
        auto f1 = [&](auto self, int pos)->void {
            for(int i = 0; i < (int)G[pos].size(); i++){
                int nex = G[pos][i].first;
                if(nex == par[pos]) continue;
                par[nex] = pos;
                self(self, nex);
                sub_siz[pos] += sub_siz[nex];
            }
        }; f1(f1, 0);
        
        int cnt = 0;
        auto f2 = [&](auto self, int pos)->void {
            in[pos] = cnt++;
            if(sub_siz[pos] == 1){
                out[pos] = cnt;
                return;
            }
            int hv = -1;
            for(int i = 0; i < (int)G[pos].size(); i++){
                int nex = G[pos][i].first;
                if(nex == par[pos]) continue;
                if(hv == -1 || sub_siz[hv] < sub_siz[nex]) hv = nex;
            }
            dep[hv] = dep[pos];
            head[hv] = head[pos];
            self(self, hv);
            for(int i = 0; i < (int)G[pos].size(); i++){
                int nex = G[pos][i].first;
                if(nex == par[pos] || nex == hv) continue;
                dep[nex] = dep[pos]+1;
                head[nex] = nex;
                self(self, nex);
            }
            out[pos] = cnt;
        }; f2(f2, 0);
        
        vector<S> node_v(n, e());
        for(int i = 0; i < n; i++){
            for(int j = 0; j < (int)G[i].size(); j++){
                if(G[i][j].first == par[i]){
                    node_v[in[i]] = G[i][j].second;
                }
            }
        }
        
        node[0] = seg_t(node_v);
        reverse(node_v.begin(), node_v.end());
        node[1] = seg_t(node_v);
    }
    
    S prod(int l, int r){
        S l_ans = e(), r_ans = e();
        while(true){
            if(dep[l] >= dep[r] && head[l] != head[r]){
                l_ans = op(l_ans, node[1].prod(n-in[l]-1, n-in[head[l]]));
                l = par[head[l]];
            } else if(dep[l] < dep[r]){
                r_ans = op(node[0].prod(in[head[r]], in[r]+1), r_ans);
                r = par[head[r]];
            } else {
                if(in[l] <= in[r]) l_ans = op(l_ans, node[0].prod(in[l]+1, in[r]+1));
                else r_ans = op(node[1].prod(n-in[l]-1, n-in[r]-1), r_ans);
                return op(l_ans, r_ans);
            }
        }
    }
    
    S prod(int r){
        return node[0].prod(in[r]+1, out[r]);
    }
    
    S get(int u, int v){
        int p = par[u] == v ? u : v;
        return node[0].get(in[p]);
    }
    
    void set(int u, int v, const S &x){
        int p = par[u] == v ? u : v;
        node[0].set(in[p], x);
        node[1].set(n-in[p]-1, x);
    }
    
    //!ここからは必須ではない（apply, LCAなど）
    
    //!未verify
    void apply(int l, int r, const F &x){
        while(true){
            if(head[l] != head[r]){
                int &lr = dep[l] < dep[r] ? r : l;
                node[0].apply(in[head[lr]], in[lr]+1, x);
                node[1].apply(n-in[lr]-1, n-in[head[lr]], x);
                lr = par[head[lr]];
            } else {
                int mi = min(in[l], in[r]);
                int ma = in[l]+in[r] - mi;
                node[0].apply(mi+1, ma+1, x);
                node[1].apply(n-ma-1, n-mi-1, x);
                break;
            }
        }
    }
    
    void apply(int r, const F &x){
        node[0].apply(in[r]+1, out[r], x);
        node[1].apply(n-out[r], n-in[r]-1, x);
    }
    
    int lca(int l, int r){
        while(true){
            if(dep[l] >= dep[r] && head[l] != head[r]) l = par[head[l]];
            else if(dep[l] < dep[r]) r = par[head[r]];
            else return in[l] < in[r] ? l : r;
        }
    }
    
    int dist(int l, int r){
        int d = 0;
        while(true){
            if(dep[l] >= dep[r] && head[l] != head[r]){
                d += in[l] - in[head[l]] + 1;
                l = par[head[l]];
            } else if(dep[l] < dep[r]){
                d += in[r] - in[head[r]] + 1;
                r = par[head[r]];
            } else return d + abs(in[l] - in[r]);
        }
    }
};

/*
    ー使い方ー
    S, op, eを決める
    コンストラクタ HLD hoge(int n) で頂点数指定
    add_edge(int u, int v, S x) で値xの無向辺追加
    その後， build() を呼び出す
    
    set(int u, int v, S x) で，頂点pの値をxに変える
    prod(int l, int r) でlからrのパスクエリ
    prod(int r) で部分木クエリ
*/


using S = pair<long long, int>;
S op(S l, S r) {return {l.first+r.first, l.second+r.second};}
S e() {return {0, 0};}
using F = long long;
S mapping(F f, S x) {return {x.first + f*x.second, x.second};}
F composition(F f, F g) {return f+g;}
F id() {return 0ll;}

int main(){
    cin.tie(0)->sync_with_stdio(0);
    
    int n, q;
    cin >> n >> q;
    HLD<S, op, e, F, mapping, composition, id> seg(n);
    
    for(int i = 0; i < n-1; i++){
        int a, b;
        cin >> a >> b;
        seg.add_edge(a, b, {0, 1});
    }
    seg.build();
    
    while(q--){
        int t, a, b;
        cin >> t >> a >> b;
        if(t == 0) cout << seg.prod(a, b).first << '\n';
        else seg.apply(a, b);
    }
}
accuracy: 1
time_ms: 270
memory_kb: 63592
final_rank: 9

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

using namespace std;

struct HLD {
    int n;
    vector<vector<int>> adj;
    vector<int> sz, in, out, head, rev, par, depth;

    HLD(int n) : n(n), adj(n), sz(n), in(n), out(n), head(n), rev(n), par(n), depth(n) {}

    void add_edge(int a, int b) {
        assert(0 <= a && a < n && 0 <= b && b < n);
        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    void dfs_sz(int v, int p, int d) {
        par[v] = p;
        sz[v] = 1;
        if (!adj[v].empty() && adj[v][0] == p) swap(adj[v][0], adj[v].back());
        for (int &s : adj[v]) {
            if (s == p) continue;
            dfs_sz(s, v, d + 1);
            sz[v] += sz[s];
            if (sz[adj[v][0]] < sz[s]) swap(adj[v][0], s);
        }
    }

    void dfs_hld(int v, int p, int &times) {
        in[v] = times++;
        rev[in[v]] = v;
        for (int &s : adj[v]) {
            if (s == p) continue;
            head[s] = adj[v][0] == s ? head[v] : s;
            dfs_hld(s, v, times);
        }
        out[v] = times;
    }

    void build() {
        dfs_sz(0, -1, 0);
        int t = 0;
        dfs_hld(0, -1, t);
    }

    int la(int v, int k) {
        while (1) {
            int u = head[v];
            if (in[v] - k >= in[u]) return rev[in[v] - k];
            k -= in[v] - in[u] + 1;
            v = par[u];
        }
    }

    int lca(int u, int v) {
        for (;; v = par[head[v]]) {
            if (in[u] > in[v]) swap(u, v);
            if (head[u] == head[v]) return u;
        }
    }

    template<typename Q, typename F, typename T>
    // qは閉区間に対応させること!!!!!!!!
    T query(int u, int v, const Q &q, const F &f, const T &e, bool edge = false) {
        T l = e, r = e;
        for (;; v = par[head[v]]) {
            if (in[u] > in[v]) swap(u, v), swap(l, r);
            if (head[u] == head[v]) break;
            l = f(q(in[head[v]], in[v]), l);
        }
        return f(f(q(in[u] + edge, in[v]), l), r);
    }

    template<typename Q>
    // qは閉区間に対応させること!!!!!!!!
    void update(int u, int v, const Q &q, bool edge = false) {
        for (;; v = par[head[v]]) {
            if (in[u] > in[v]) swap(u, v);
            if (head[u] == head[v]) break;
            q(in[head[v]], in[v]);
        }
        q(in[u] + edge, in[v]);
    }
};

class BIT {
    int n;
    vector<int> data0, data1;

    void add(vector<int> &data, int i, int x) {
        while (i <= n) {
            data[i] += x;
            i += i & -i;
        }
    }

    int sum(vector<int> &data, int i) {
        int s = 0;
        while (i > 0) {
            s += data[i];
            i -= i & -i;
        }
        return s;
    }

public:
    BIT(int n) : n(n), data0(n + 1), data1(n + 1) {}

    // [l, r)
    void add(int l, int r, int x) {
        l++;
        r++;
        add(data0, l, -x * (l - 1));
        add(data1, l, x);
        add(data0, r, x * (r - 1));
        add(data1, r, -x);
    }

    // [l, r)
    int sum(int l, int r) {
        int s = 0;
        s += sum(data0, r) + sum(data1, r) * r;
        s -= sum(data0, l) + sum(data1, l) * l;
        return s;
    }
};

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

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


    auto sum = [&](int u, int v) {
        return bit.sum(u, v + 1);
    };

    while (q--) {
        int t;
        cin >> t;
        if (t == 0) {
            int u, v;
            cin >> u >> v;
            cout << hld.query(u, v, sum, [](int a, int b) { return a + b; }, 0ll, true) << '\n';
        } else {
            int v, x;
            cin >> v >> x;
            // こっちは半開区間
            // 辺クエリなので1足している
            bit.add(hld.in[v] + 1, hld.out[v], x);
        }
    }
}
accuracy: 1
time_ms: 110
memory_kb: 33540
final_rank: 1

code_snippet: //
// Euler Tour (update for nodes)
//
// verified:
//   ABC 406 F - Compare Tree Weights
//     https://atcoder.jp/contests/abc406/tasks/abc406_f
//
//   AOJ 2667 Tree
//     http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2667
//

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


// Run Tree (including Euler Tour)
template<class Graph = vector<vector<int>>> struct RunTree {
    // id[v][w] := the index of node w in G[v]
    vector<unordered_map<int, int>> id;

    // num[v][i] := the size of subtree of G[v][i] with parent v
    vector<vector<long long>> num;
    
    // for finding lca
    int root;
    vector<vector<int>> parent;
    vector<int> depth;

    // Euler tour
    vector<int> tour; // the node-number of i-th element of Euler-tour
    vector<int> v_s_id, v_t_id; // the index of Euler-tour of node v
    vector<int> e_id; // the index of edge e (v*2 + (0: root to leaf, 1: leaf to root))

    // constructor
    RunTree() {}
    RunTree(const Graph &G, int root = 0) : root(root) {
        init(G, root);
    }
    
    // init
    void init(const Graph &G, int root = 0) {
        int N = (int)G.size();
        id.assign(N, unordered_map<int,int>()), num.assign(N, vector<long long>());
        for (int v = 0; v < N; v++) num[v].assign((int)G[v].size(), 0);
        int h = 1, ord = 0;
        while ((1<<h) < N) h++;
        parent.assign(h, vector<int>(N, -1)), depth.resize(N);
        tour.resize(N*2-1), v_s_id.resize(N), v_t_id.resize(N), e_id.resize(N*2);
        rec(G, root, -1, 0, ord);
        for (int i = 0; i+1 < (int)parent.size(); ++i) {
            for (int v = 0; v < N; v++)
                if (parent[i][v] != -1)
                    parent[i+1][v] = parent[i][parent[i][v]];
        }
    }

    // get_size(u, v) := the size of subtree v with parent u
    long long get_size(int u, int v) {
        return num[u][id[u][v]];
    }

    // get first / last id of node v in Euler tour
    int vs(int v) { return v_s_id[v]; }
    int vt(int v) { return v_t_id[v]; }

    // get edge-id of (pv, v) in Euler tour
    int e(int v, bool leaf_to_root = false) {
        assert(v != root);
        if (!leaf_to_root) return e_id[v * 2];
        else return e_id[v * 2 + 1];
    }
    int e(int u, int v) {
        if (depth[u] < depth[v]) return e(v);
        else return e(u, false);
    }

    // lca(u, v)
    int get_lca(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int i = 0; i < (int)parent.size(); i++) {
            if ((depth[v] - depth[u]) & (1<<i))
                v = parent[i][v];
        }
        if (u == v) return u;
        for (int i = (int)parent.size()-1; i >= 0; i--) {
            if (parent[i][u] != parent[i][v]) {
                u = parent[i][u];
                v = parent[i][v];
            }
        }
        return parent[0][u];
    }

    // dist(u, v)
    long long get_dist(int u, int v) {
        int lca = get_lca(u, v);
        return depth[u] + depth[v] - depth[lca]*2;
    }

    // get_parent(v, p) := the parent of v directed for p
    int get_parent(int v, int p) {
        if (v == p) return -1;
        int lca = get_lca(v, p);
        if (lca != v) return parent[0][v];
        for (int i = (int)parent.size()-1; i >= 0; i--) {
            if (parent[i][p] != -1 && depth[parent[i][p]] > depth[v]) {
                p = parent[i][p];
            }
        }
        return p;
    }
    
    // rec
    int rec(const Graph &G, int v, int p, int d, int &ord) {
        int p_index = -1;
        int sum = 1;
        parent[0][v] = p, depth[v] = d;
        tour[ord] = v, v_s_id[v] = v_t_id[v] = ord;
        ord++;
        for (int i = 0; i < (int)G[v].size(); i++) {
            int ch = G[v][i];
            id[v][ch] = i;
            if (ch == p) {
                p_index = i;
                continue;
            }
            e_id[ch * 2] = ord - 1;
            int s = rec(G, ch, v, d+1, ord);
            num[v][i] = s;
            sum += s;
            tour[ord] = v;
            v_t_id[v] = ord;
            e_id[ch * 2 + 1] = ord - 1;
            ord++;
        }
        if (p_index != -1) num[v][p_index] = (int)G.size() - sum;
        return sum;
    }
};



//------------------------------//
// Examples
//------------------------------//


// ABC 406 F - Compare Tree Weights
template <class Abel> struct BIT {
    Abel UNITY_SUM = 0;
    vector<Abel> dat;
    
    // [0, n)
    BIT(int n, Abel unity = 0) : UNITY_SUM(unity), dat(n, unity) { }
    void init(int n) {
        dat.assign(n, UNITY_SUM);
    }
    
    // a is 0-indexed
    inline void add(int a, Abel x) {
        for (int i = a; i < (int)dat.size(); i |= i + 1)
            dat[i] = dat[i] + x;
    }
    
    // [0, a), a is 0-indexed
    inline Abel sum(int a) {
        Abel res = UNITY_SUM;
        for (int i = a - 1; i >= 0; i = (i & (i + 1)) - 1)
            res = res + dat[i];
        return res;
    }
    
    // [a, b), a and b are 0-indexed
    inline Abel sum(int a, int b) {
        return sum(b) - sum(a);
    }
    
    // debug
    void print() {
        for (int i = 0; i < (int)dat.size(); ++i)
            cout << sum(i, i + 1) << ",";
        cout << endl;
    }
};

void ABC_406_F() {
    using Graph = vector<vector<int>>;
    int N, Q, u, v;
    cin >> N;
    Graph G(N);
    vector<pair<int,int>> edges(N-1);
    for (int i = 0; i < N-1; i++) {
        cin >> u >> v, u--, v--;
        edges[i] = {u, v};
        G[u].push_back(v), G[v].push_back(u);
    }
    RunTree rt(G);
    cin >> Q;
    long long all = 0;
    BIT<long long> bit(rt.tour.size() + 1);
    for (int qid = 0; qid < Q; qid++) {
        long long type, v, x, y;
        cin >> type;
        if (type == 1) {
            cin >> v >> x, v--;
            bit.add(rt.vs(v), x);
            all += x;
        } else if (type == 2) {
            cin >> y, y--;
            int u = edges[y].first, v = edges[y].second;
            if (rt.depth[u] > rt.depth[v]) swap(u, v);

            long long uv_size = rt.get_size(u, v), vu_size = rt.get_size(v, u);
            long long uv_sum = bit.sum(rt.vs(v), rt.vt(v)+1);  // +1 is necessary!
            long long vu_sum = all - uv_sum;
            long long uv = uv_size + uv_sum, vu = vu_size + vu_sum;
            long long res = abs(uv - vu);
            cout << res << '\n';
        } 
    }
}


// AOJ 2667 Tree
// Lazy Segment Tree
template<class Monoid, class Action> struct LazySegmentTree {
    // various function types
    using FuncMonoid = function<Monoid(Monoid, Monoid)>;
    using FuncAction = function<Monoid(Action, Monoid)>;
    using FuncComposition = function<Action(Action, Action)>;

    // core member
    int N;
    FuncMonoid OP;
    FuncAction ACT;
    FuncComposition COMP;
    Monoid IDENTITY_MONOID;
    Action IDENTITY_ACTION;
    
    // inner data
    int log, offset;
    vector<Monoid> dat;
    vector<Action> lazy;
    
    // constructor
    LazySegmentTree() {}
    LazySegmentTree(int n, const FuncMonoid op, const FuncAction act, const FuncComposition comp,
                    const Monoid &identity_monoid, const Action &identity_action) {
        init(n, op, act, comp, identity_monoid, identity_action);
    }
    LazySegmentTree(const vector<Monoid> &v,
                    const FuncMonoid op, const FuncAction act, const FuncComposition comp,
                    const Monoid &identity_monoid, const Action &identity_action) {
        init(v, op, act, comp, identity_monoid, identity_action);
    }
    void init(int n, const FuncMonoid op, const FuncAction act, const FuncComposition comp,
              const Monoid &identity_monoid, const Action &identity_action) {
        N = n, OP = op, ACT = act, COMP = comp;
        IDENTITY_MONOID = identity_monoid, IDENTITY_ACTION = identity_action;
        log = 0, offset = 1;
        while (offset < N) ++log, offset <<= 1;
        dat.assign(offset * 2, IDENTITY_MONOID);
        lazy.assign(offset * 2, IDENTITY_ACTION);
    }
    void init(const vector<Monoid> &v,
              const FuncMonoid op, const FuncAction act, const FuncComposition comp,
              const Monoid &identity_monoid, const Action &identity_action) {
        init((int)v.size(), op, act, comp, identity_monoid, identity_action);
        build(v);
    }
    void build(const vector<Monoid> &v) {
        assert(N == (int)v.size());
        for (int i = 0; i < N; ++i) dat[i + offset] = v[i];
        for (int k = offset - 1; k > 0; --k) pull_dat(k);
    }
    int size() const {
        return N;
    }
    
    // basic functions for lazy segment tree
    void pull_dat(int k) {
        dat[k] = OP(dat[k * 2], dat[k * 2 + 1]);
    }
    void apply_lazy(int k, const Action &f) {
        dat[k] = ACT(f, dat[k]);
        if (k < offset) lazy[k] = COMP(f, lazy[k]);
    }
    void push_lazy(int k) {
        apply_lazy(k * 2, lazy[k]);
        apply_lazy(k * 2 + 1, lazy[k]);
        lazy[k] = IDENTITY_ACTION;
    }
    void pull_dat_deep(int k) {
        for (int h = 1; h <= log; ++h) pull_dat(k >> h);
    }
    void push_lazy_deep(int k) {
        for (int h = log; h >= 1; --h) push_lazy(k >> h);
    }
    
    // setter and getter, update A[i], i is 0-indexed, O(log N)
    void set(int i, const Monoid &v) {
        assert(0 <= i && i < N);
        int k = i + offset;
        push_lazy_deep(k);
        dat[k] = v;
        pull_dat_deep(k);
    }
    Monoid get(int i) {
        assert(0 <= i && i < N);
        int k = i + offset;
        push_lazy_deep(k);
        return dat[k];
    }
    Monoid operator [] (int i) {
        return get(i);
    }
    
    // apply f for index i
    void apply(int i, const Action &f) {
        assert(0 <= i && i < N);
        int k = i + offset;
        push_lazy_deep(k);
        dat[k] = ACT(f, dat[k]);
        pull_dat_deep(k);
    }
    // apply f for interval [l, r)
    void apply(int l, int r, const Action &f) {
        assert(0 <= l && l <= r && r <= N);
        if (l == r) return;
        l += offset, r += offset;
        for (int h = log; h >= 1; --h) {
            if (((l >> h) << h) != l) push_lazy(l >> h);
            if (((r >> h) << h) != r) push_lazy((r - 1) >> h);
        }
        int original_l = l, original_r = r;
        for (; l < r; l >>= 1, r >>= 1) {
            if (l & 1) apply_lazy(l++, f);
            if (r & 1) apply_lazy(--r, f);
        }
        l = original_l, r = original_r;
        for (int h = 1; h <= log; ++h) {
            if (((l >> h) << h) != l) pull_dat(l >> h);
            if (((r >> h) << h) != r) pull_dat((r - 1) >> h);
        }
    }
    
    // get prod of interval [l, r)
    Monoid prod(int l, int r) {
        assert(0 <= l && l <= r && r <= N);
        if (l == r) return IDENTITY_MONOID;
        l += offset, r += offset;
        for (int h = log; h >= 1; --h) {
            if (((l >> h) << h) != l) push_lazy(l >> h);
            if (((r >> h) << h) != r) push_lazy(r >> h);
        }
        Monoid val_left = IDENTITY_MONOID, val_right = IDENTITY_MONOID;
        for (; l < r; l >>= 1, r >>= 1) {
            if (l & 1) val_left = OP(val_left, dat[l++]);
            if (r & 1) val_right = OP(dat[--r], val_right);
        }
        return OP(val_left, val_right);
    }
    Monoid all_prod() {
        return dat[1];
    }
    
    // get max r that f(get(l, r)) = True (0-indexed), O(log N)
    // f(IDENTITY) need to be True
    int max_right(const function<bool(Monoid)> f, int l = 0) {
        if (l == N) return N;
        l += offset;
        push_lazy_deep(l);
        Monoid sum = IDENTITY_MONOID;
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(OP(sum, dat[l]))) {
                while (l < offset) {
                    push_lazy(l);
                    l = l * 2;
                    if (f(OP(sum, dat[l]))) {
                        sum = OP(sum, dat[l]);
                        ++l;
                    }
                }
                return l - offset;
            }
            sum = OP(sum, dat[l]);
            ++l;
        } while ((l & -l) != l);  // stop if l = 2^e
        return N;
    }

    // get min l that f(get(l, r)) = True (0-indexed), O(log N)
    // f(IDENTITY) need to be True
    int min_left(const function<bool(Monoid)> f, int r = -1) {
        if (r == 0) return 0;
        if (r == -1) r = N;
        r += offset;
        push_lazy_deep(r - 1);
        Monoid sum = IDENTITY_MONOID;
        do {
            --r;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(OP(dat[r], sum))) {
                while (r < offset) {
                    push_lazy(r);
                    r = r * 2 + 1;
                    if (f(OP(dat[r], sum))) {
                        sum = OP(dat[r], sum);
                        --r;
                    }
                }
                return r + 1 - offset;
            }
            sum = OP(dat[r], sum);
        } while ((r & -r) != r);
        return 0;
    }
    
    // debug stream
    friend ostream& operator << (ostream &s, LazySegmentTree seg) {
        for (int i = 0; i < (int)seg.size(); ++i) {
            s << seg[i];
            if (i != (int)seg.size() - 1) s << " ";
        }
        return s;
    }
    
    // dump
    void dump() {
        for (int i = 0; i <= log; ++i) {
            for (int j = (1 << i); j < (1 << (i + 1)); ++j) {
                cout << "{" << dat[j] << "," << lazy[j] << "} ";
            }
            cout << endl;
        }
    }
};

void AOJ_2667() {
    int N, Q;
    cin >> N >> Q;
    vector<vector<int>> G(N);
    for (int i = 0; i < N-1; ++i) {
        int a, b;
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    RunTree rt(G);
    using Node = pair<long long, int>;
    auto fm = [&](Node a, Node b) { return Node(a.first + b.first, a.second + b.second); };
    auto fa = [&](long long d, Node a) { a.first += d * a.second; return a; };
    auto fl = [&](long long d, long long e) { return d + e; };
    LazySegmentTree<Node, long long> seg(N*2, fm, fa, fl, Node(0, 0), 0);
    for (int v = 1; v < N; v++) {
        seg.set(rt.e(v, false), Node(0, 1));
        seg.set(rt.e(v, true), Node(0, -1));
    }
    
    for (int q = 0; q < Q; ++q) {
        int type;
        cin >> type;
        if (type == 0) {
            int u, v;
            cin >> u >> v;
            int l = rt.get_lca(u, v);
            long long res = seg.prod(0, rt.vs(u)).first
             + seg.prod(0, rt.vs(v)).first
             - seg.prod(0, rt.vs(l)).first * 2;
            cout << res << '\n';
        } else {
            int u, x;
            cin >> u >> x;
            seg.apply(rt.vs(u), rt.vt(u), x);
        }
    }
}


int main () {
    //ABC_406_F();
    AOJ_2667();
}
accuracy: 1
time_ms: 550
memory_kb: 97424
final_rank: 18

code_snippet: //
// Euler Tour (update for nodes)
//
// verified:
//   ABC 406 F - Compare Tree Weights
//     https://atcoder.jp/contests/abc406/tasks/abc406_f
//
//   AOJ 2667 Tree
//     http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2667
//

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


using pint = pair<int, int>;
using pll = pair<long long, long long>;
using tint = array<int, 3>;
using tll = array<long long, 3>;
using fint = array<int, 4>;
using fll = array<long long, 4>;
using vint = vector<int>;
using vll = vector<long long>;
using ll = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
template <class T>
using min_priority_queue = priority_queue<T, vector<T>, greater<T>>;

#define REP(i, a) for (long long i = 0; i < (long long)(a); i++)
#define REP2(i, a, b) for (long long i = a; i < (long long)(b); i++)
#define RREP(i, a) for (long long i = (a)-1; i >= (long long)(0); --i)
#define RREP2(i, a, b) for (long long i = (b)-1; i >= (long long)(a); --i)
#define EB emplace_back
#define PB push_back
#define MP make_pair
#define MT make_tuple
#define FI first
#define SE second
#define ALL(x) x.begin(), x.end()
#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl

// debug stream
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, deque<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T> ostream& operator << (ostream &s, multiset<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; }




// Run Tree (including Euler Tour)
template<class Graph = vector<vector<int>>> struct RunTree {
    // id[v][w] := the index of node w in G[v]
    vector<unordered_map<int, int>> id;

    // num[v][i] := the size of subtree of G[v][i] with parent v
    vector<vector<long long>> num;
    
    // for finding lca
    int root;
    vector<vector<int>> parent;
    vector<int> depth;

    // Euler tour
    vector<int> tour; // the node-number of i-th element of Euler-tour
    vector<int> v_s_id, v_t_id; // the index of Euler-tour of node v
    vector<int> e_id; // the index of edge e (v*2 + (0: root to leaf, 1: leaf to root))

    // constructor
    RunTree() {}
    RunTree(const Graph &G, int root = 0) : root(root) {
        init(G, root);
    }
    
    // init
    void init(const Graph &G, int root = 0) {
        int N = (int)G.size();
        id.assign(N, unordered_map<int,int>()), num.assign(N, vector<long long>());
        for (int v = 0; v < N; v++) num[v].assign((int)G[v].size(), 0);
        int h = 1, ord = 0;
        while ((1<<h) < N) h++;
        parent.assign(h, vector<int>(N, -1)), depth.resize(N);
        tour.resize(N*2-1), v_s_id.resize(N), v_t_id.resize(N), e_id.resize(N*2);
        rec(G, root, -1, 0, ord);
        for (int i = 0; i+1 < (int)parent.size(); ++i) {
            for (int v = 0; v < N; v++)
                if (parent[i][v] != -1)
                    parent[i+1][v] = parent[i][parent[i][v]];
        }
    }

    // get_size(u, v) := the size of subtree v with parent u
    long long get_size(int u, int v) {
        return num[u][id[u][v]];
    }

    // get first / last id of node v in Euler tour
    int vs(int v) { return v_s_id[v]; }
    int vt(int v) { return v_t_id[v]; }

    // get edge-id of (pv, v) in Euler tour
    int e(int v, bool root_to_leaf = true) {
        assert(v != root);
        if (root_to_leaf) return e_id[v * 2];
        else return e_id[v * 2 + 1];
    }
    int e(int u, int v) {
        if (depth[u] < depth[v]) return e(v);
        else return e(u, false);
    }

    // lca(u, v)
    int get_lca(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int i = 0; i < (int)parent.size(); i++) {
            if ((depth[v] - depth[u]) & (1<<i))
                v = parent[i][v];
        }
        if (u == v) return u;
        for (int i = (int)parent.size()-1; i >= 0; i--) {
            if (parent[i][u] != parent[i][v]) {
                u = parent[i][u];
                v = parent[i][v];
            }
        }
        return parent[0][u];
    }

    // dist(u, v)
    long long get_dist(int u, int v) {
        int lca = get_lca(u, v);
        return depth[u] + depth[v] - depth[lca]*2;
    }

    // get_parent(v, p) := the parent of v directed for p
    int get_parent(int v, int p) {
        if (v == p) return -1;
        int lca = get_lca(v, p);
        if (lca != v) return parent[0][v];
        for (int i = (int)parent.size()-1; i >= 0; i--) {
            if (parent[i][p] != -1 && depth[parent[i][p]] > depth[v]) {
                p = parent[i][p];
            }
        }
        return p;
    }
    
    // rec
    int rec(const Graph &G, int v, int p, int d, int &ord) {
        int p_index = -1;
        int sum = 1;
        parent[0][v] = p, depth[v] = d;
        tour[ord] = v, v_s_id[v] = v_t_id[v] = ord;
        ord++;
        for (int i = 0; i < (int)G[v].size(); i++) {
            int ch = G[v][i];
            id[v][ch] = i;
            if (ch == p) {
                p_index = i;
                continue;
            }
            e_id[ch * 2] = ord - 1;
            int s = rec(G, ch, v, d+1, ord);
            num[v][i] = s;
            sum += s;
            tour[ord] = v;
            v_t_id[v] = ord;
            e_id[ch * 2 + 1] = ord - 1;
            ord++;
        }
        if (p_index != -1) num[v][p_index] = (int)G.size() - sum;
        return sum;
    }
};



//------------------------------//
// Examples
//------------------------------//


// ABC 406 F - Compare Tree Weights
template <class Abel> struct BIT {
    Abel UNITY_SUM = 0;
    vector<Abel> dat;
    
    // [0, n)
    BIT(int n, Abel unity = 0) : UNITY_SUM(unity), dat(n, unity) { }
    void init(int n) {
        dat.assign(n, UNITY_SUM);
    }
    
    // a is 0-indexed
    inline void add(int a, Abel x) {
        for (int i = a; i < (int)dat.size(); i |= i + 1)
            dat[i] = dat[i] + x;
    }
    
    // [0, a), a is 0-indexed
    inline Abel sum(int a) {
        Abel res = UNITY_SUM;
        for (int i = a - 1; i >= 0; i = (i & (i + 1)) - 1)
            res = res + dat[i];
        return res;
    }
    
    // [a, b), a and b are 0-indexed
    inline Abel sum(int a, int b) {
        return sum(b) - sum(a);
    }
    
    // debug
    void print() {
        for (int i = 0; i < (int)dat.size(); ++i)
            cout << sum(i, i + 1) << ",";
        cout << endl;
    }
};

void ABC_406_F() {
    using Graph = vector<vector<int>>;
    int N, Q, u, v;
    cin >> N;
    Graph G(N);
    vector<pair<int,int>> edges(N-1);
    for (int i = 0; i < N-1; i++) {
        cin >> u >> v, u--, v--;
        edges[i] = {u, v};
        G[u].push_back(v), G[v].push_back(u);
    }
    RunTree rt(G);
    cin >> Q;
    long long all = 0;
    BIT<long long> bit(rt.tour.size() + 1);
    for (int qid = 0; qid < Q; qid++) {
        long long type, v, x, y;
        cin >> type;
        if (type == 1) {
            cin >> v >> x, v--;
            bit.add(rt.vs(v), x);
            all += x;
        } else if (type == 2) {
            cin >> y, y--;
            int u = edges[y].first, v = edges[y].second;
            if (rt.depth[u] > rt.depth[v]) swap(u, v);

            long long uv_size = rt.get_size(u, v), vu_size = rt.get_size(v, u);
            long long uv_sum = bit.sum(rt.vs(v), rt.vt(v)+1);  // +1 is necessary!
            long long vu_sum = all - uv_sum;
            long long uv = uv_size + uv_sum, vu = vu_size + vu_sum;
            long long res = abs(uv - vu);
            cout << res << '\n';
        } 
    }
}


// AOJ 2667 Tree
// Lazy Segment Tree
template<class Monoid, class Action> struct LazySegmentTree {
    // various function types
    using FuncMonoid = function<Monoid(Monoid, Monoid)>;
    using FuncAction = function<Monoid(Action, Monoid)>;
    using FuncComposition = function<Action(Action, Action)>;

    // core member
    int N;
    FuncMonoid OP;
    FuncAction ACT;
    FuncComposition COMP;
    Monoid IDENTITY_MONOID;
    Action IDENTITY_ACTION;
    
    // inner data
    int log, offset;
    vector<Monoid> dat;
    vector<Action> lazy;
    
    // constructor
    LazySegmentTree() {}
    LazySegmentTree(int n, const FuncMonoid op, const FuncAction act, const FuncComposition comp,
                    const Monoid &identity_monoid, const Action &identity_action) {
        init(n, op, act, comp, identity_monoid, identity_action);
    }
    LazySegmentTree(const vector<Monoid> &v,
                    const FuncMonoid op, const FuncAction act, const FuncComposition comp,
                    const Monoid &identity_monoid, const Action &identity_action) {
        init(v, op, act, comp, identity_monoid, identity_action);
    }
    void init(int n, const FuncMonoid op, const FuncAction act, const FuncComposition comp,
              const Monoid &identity_monoid, const Action &identity_action) {
        N = n, OP = op, ACT = act, COMP = comp;
        IDENTITY_MONOID = identity_monoid, IDENTITY_ACTION = identity_action;
        log = 0, offset = 1;
        while (offset < N) ++log, offset <<= 1;
        dat.assign(offset * 2, IDENTITY_MONOID);
        lazy.assign(offset * 2, IDENTITY_ACTION);
    }
    void init(const vector<Monoid> &v,
              const FuncMonoid op, const FuncAction act, const FuncComposition comp,
              const Monoid &identity_monoid, const Action &identity_action) {
        init((int)v.size(), op, act, comp, identity_monoid, identity_action);
        build(v);
    }
    void build(const vector<Monoid> &v) {
        assert(N == (int)v.size());
        for (int i = 0; i < N; ++i) dat[i + offset] = v[i];
        for (int k = offset - 1; k > 0; --k) pull_dat(k);
    }
    int size() const {
        return N;
    }
    
    // basic functions for lazy segment tree
    void pull_dat(int k) {
        dat[k] = OP(dat[k * 2], dat[k * 2 + 1]);
    }
    void apply_lazy(int k, const Action &f) {
        dat[k] = ACT(f, dat[k]);
        if (k < offset) lazy[k] = COMP(f, lazy[k]);
    }
    void push_lazy(int k) {
        apply_lazy(k * 2, lazy[k]);
        apply_lazy(k * 2 + 1, lazy[k]);
        lazy[k] = IDENTITY_ACTION;
    }
    void pull_dat_deep(int k) {
        for (int h = 1; h <= log; ++h) pull_dat(k >> h);
    }
    void push_lazy_deep(int k) {
        for (int h = log; h >= 1; --h) push_lazy(k >> h);
    }
    
    // setter and getter, update A[i], i is 0-indexed, O(log N)
    void set(int i, const Monoid &v) {
        assert(0 <= i && i < N);
        int k = i + offset;
        push_lazy_deep(k);
        dat[k] = v;
        pull_dat_deep(k);
    }
    Monoid get(int i) {
        assert(0 <= i && i < N);
        int k = i + offset;
        push_lazy_deep(k);
        return dat[k];
    }
    Monoid operator [] (int i) {
        return get(i);
    }
    
    // apply f for index i
    void apply(int i, const Action &f) {
        assert(0 <= i && i < N);
        int k = i + offset;
        push_lazy_deep(k);
        dat[k] = ACT(f, dat[k]);
        pull_dat_deep(k);
    }
    // apply f for interval [l, r)
    void apply(int l, int r, const Action &f) {
        assert(0 <= l && l <= r && r <= N);
        if (l == r) return;
        l += offset, r += offset;
        for (int h = log; h >= 1; --h) {
            if (((l >> h) << h) != l) push_lazy(l >> h);
            if (((r >> h) << h) != r) push_lazy((r - 1) >> h);
        }
        int original_l = l, original_r = r;
        for (; l < r; l >>= 1, r >>= 1) {
            if (l & 1) apply_lazy(l++, f);
            if (r & 1) apply_lazy(--r, f);
        }
        l = original_l, r = original_r;
        for (int h = 1; h <= log; ++h) {
            if (((l >> h) << h) != l) pull_dat(l >> h);
            if (((r >> h) << h) != r) pull_dat((r - 1) >> h);
        }
    }
    
    // get prod of interval [l, r)
    Monoid prod(int l, int r) {
        assert(0 <= l && l <= r && r <= N);
        if (l == r) return IDENTITY_MONOID;
        l += offset, r += offset;
        for (int h = log; h >= 1; --h) {
            if (((l >> h) << h) != l) push_lazy(l >> h);
            if (((r >> h) << h) != r) push_lazy(r >> h);
        }
        Monoid val_left = IDENTITY_MONOID, val_right = IDENTITY_MONOID;
        for (; l < r; l >>= 1, r >>= 1) {
            if (l & 1) val_left = OP(val_left, dat[l++]);
            if (r & 1) val_right = OP(dat[--r], val_right);
        }
        return OP(val_left, val_right);
    }
    Monoid all_prod() {
        return dat[1];
    }
    
    // get max r that f(get(l, r)) = True (0-indexed), O(log N)
    // f(IDENTITY) need to be True
    int max_right(const function<bool(Monoid)> f, int l = 0) {
        if (l == N) return N;
        l += offset;
        push_lazy_deep(l);
        Monoid sum = IDENTITY_MONOID;
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(OP(sum, dat[l]))) {
                while (l < offset) {
                    push_lazy(l);
                    l = l * 2;
                    if (f(OP(sum, dat[l]))) {
                        sum = OP(sum, dat[l]);
                        ++l;
                    }
                }
                return l - offset;
            }
            sum = OP(sum, dat[l]);
            ++l;
        } while ((l & -l) != l);  // stop if l = 2^e
        return N;
    }

    // get min l that f(get(l, r)) = True (0-indexed), O(log N)
    // f(IDENTITY) need to be True
    int min_left(const function<bool(Monoid)> f, int r = -1) {
        if (r == 0) return 0;
        if (r == -1) r = N;
        r += offset;
        push_lazy_deep(r - 1);
        Monoid sum = IDENTITY_MONOID;
        do {
            --r;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(OP(dat[r], sum))) {
                while (r < offset) {
                    push_lazy(r);
                    r = r * 2 + 1;
                    if (f(OP(dat[r], sum))) {
                        sum = OP(dat[r], sum);
                        --r;
                    }
                }
                return r + 1 - offset;
            }
            sum = OP(dat[r], sum);
        } while ((r & -r) != r);
        return 0;
    }
    
    // debug stream
    friend ostream& operator << (ostream &s, LazySegmentTree seg) {
        for (int i = 0; i < (int)seg.size(); ++i) {
            s << seg[i];
            if (i != (int)seg.size() - 1) s << " ";
        }
        return s;
    }
    
    // dump
    void dump() {
        for (int i = 0; i <= log; ++i) {
            for (int j = (1 << i); j < (1 << (i + 1)); ++j) {
                cout << "{" << dat[j] << "," << lazy[j] << "} ";
            }
            cout << endl;
        }
    }
};

void AOJ_2667() {
    int N, Q;
    cin >> N >> Q;
    vector<vector<int>> G(N);
    for (int i = 0; i < N-1; ++i) {
        int a, b;
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    RunTree rt(G);
    using Node = pair<long long, int>;
    auto fm = [&](Node a, Node b) { return Node(a.first + b.first, a.second + b.second); };
    auto fa = [&](long long d, Node a) { a.first += d * a.second; return a; };
    auto fl = [&](long long d, long long e) { return d + e; };
    LazySegmentTree<Node, long long> seg(N*2, fm, fa, fl, Node(0, 0), 0);
    for (int v = 1; v < N; v++) {
        seg.set(rt.e(v, true), Node(0, 1));
        seg.set(rt.e(v, false), Node(0, -1));
    }
    
    for (int q = 0; q < Q; ++q) {
        int type;
        cin >> type;
        if (type == 0) {
            int u, v;
            cin >> u >> v;
            int l = rt.get_lca(u, v);
            long long res = seg.prod(0, rt.vs(u)).first
             + seg.prod(0, rt.vs(v)).first
             - seg.prod(0, rt.vs(l)).first * 2;
            cout << res << '\n';

            // COUT(seg); COUT(u); COUT(v); COUT(l); COUT(rt.tour); COUT(rt.vs(u)); COUT(rt.vs(v)); 
            // COUT(rt.vs(l)); COUT(seg.prod(0, rt.vs(u)).first); COUT(seg.prod(0, rt.vs(v)).first);
            // COUT(seg.prod(0, rt.vs(l)).first);
        } else {
            int u, x;
            cin >> u >> x;
            seg.apply(rt.vs(u), rt.vt(u), x);

            //COUT(seg); COUT(u); COUT(rt.vs(u)); COUT(rt.vt(u)); COUT(rt.e_id);
        }
    }
}


int main () {
    //ABC_406_F();
    AOJ_2667();
}
accuracy: 1
time_ms: 550
memory_kb: 97484
final_rank: 19

code_snippet: #include <iterator>
#include <bits/stdc++.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <utility>
#include <vector>

using namespace std;

struct HLD {
    int n;
    vector<vector<int>> g;
    vector<int> euler, pos, dep, siz, per, root;
    vector<pair<int, pair<int, int>>> range;
    HLD(vector<vector<int>> g) : n(g.size()), g(g) {
        dep.resize(n, -1);
        per.resize(n, -1);
        pos.resize(n, -1);
        root.resize(n, -1);
        siz.resize(n, 1);
        euler.reserve(n);
        range.resize(n, {-1, {-1, -1}});
        {
            auto dfs = [&](int c, auto dfs) -> int {
                for (int i : g[c]) {
                    if (dep[i] != -1) continue;
                    per[i] = c;
                    dep[i] = dep[c] + 1;
                    siz[c] += dfs(i, dfs);
                }
                return siz[c];
            };
            per[0] = 0;
            dep[0] = 0;
            dfs(0, dfs);
        }
        {
            auto dfs = [&](int c, int r, auto dfs) -> void {
                pos[c] = euler.size();
                euler.push_back(c);
                range[c].first = pos[c];
                range[r].second.first = pos[c];
                root[c] = r;
                pair<int, int> mx(-1, -1);
                for (int i : g[c]) {
                    if (dep[i] < dep[c]) continue;
                    if (mx.second < siz[i]) {
                        mx = {i, siz[i]};
                    }
                }
                if (mx.first != -1) {
                    dfs(mx.first, r, dfs);
                }
                for (int i : g[c]) {
                    if (dep[i] < dep[c]) continue;
                    if (i != mx.first) {
                        dfs(i, i, dfs);
                    }
                }
                range[c].second.second = (int)euler.size() - 1;
            };
            dfs(0, 0, dfs);
        }
    }
    vector<pair<int, int>> route(int u, int v) {
        vector<pair<int, int>> res;
        while (root[u] != root[v]) {
            if (dep[root[v]] < dep[root[u]]) {
                res.emplace_back(make_pair(range[root[u]].first, pos[u]));
                u = per[root[u]];
            } else {
                res.emplace_back(make_pair(range[root[v]].first, pos[v]));
                v = per[root[v]];
            }
        }
        res.emplace_back(make_pair(min(pos[u], pos[v]), max(pos[u], pos[v])));
        return res;
    }
    pair<int, int> part(int u) {
        return make_pair(range[u].first, range[u].second.second);
    }
    int lca(int u, int v) {
        vector<pair<int, int>> res = route(u, v);
        return euler[res.back().first];
    }
    int size(int u) {
        return siz[u];
    }
    int depth(int u) {
        return dep[u];
    }
};


struct FASTIO {
    static constexpr int buffer_size = 1 << 20;
    char output_buffer[buffer_size];
    char *ipos, *obegin, *oend, *opos;
    struct stat st;
    explicit FASTIO() : obegin(output_buffer),
                        oend(output_buffer + buffer_size),
                        opos(output_buffer) {
        fstat(0, &st);
        ipos = (char *)mmap(nullptr, st.st_size + 64, PROT_READ, MAP_PRIVATE, 0, 0);
    }
    ~FASTIO() noexcept { this->flush(); }

    inline void seek() noexcept {
        while (*ipos <= ' ') [[unlikely]] {
            ++ipos;
        }
    }

    inline void flush() noexcept {
        ignore = ::write(1, obegin, opos - obegin);
        opos = obegin;
    }

    inline void reserve(int x) noexcept {
        if (oend - opos < x) [[unlikely]] {
            flush();
        }
    }
} FIO;

#define cin FIO
#define cout FIO

inline FASTIO& operator<<(FASTIO& io, char c) noexcept {
    io.reserve(1);
    *io.opos++ = c;
    return io;
}

template <unsigned_integral T>
inline FASTIO& operator>>(FASTIO& io, T& x) noexcept {
    io.seek();
    common_type_t<T, uint64_t> y = 0;
    while (true) {
        uint64_t v;
        memcpy(&v, io.ipos, 8);
        if ((v -= 0x3030303030303030) & 0x8080808080808080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff00ff00ff00ff;
        v = (v * 100 + (v >> 16)) & 0xffff0000ffff;
        v = (v * 10000 + (v >> 32)) & 0xffffffff;
        y = 100000000 * y + v;
        io.ipos += 8;
    }
    while (true) {
        uint32_t v;
        memcpy(&v, io.ipos, 4);
        if ((v -= 0x30303030) & 0x80808080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff00ff;
        v = (v * 100 + (v >> 16)) & 0xffff;
        y = 10000 * y + v;
        io.ipos += 4;
    }
    while (true) {
        uint16_t v;
        memcpy(&v, io.ipos, 2);
        if ((v -= 0x3030) & 0x8080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff;
        y = 100 * y + v;
        io.ipos += 2;
    }
    while (' ' < *io.ipos) {
        y *= 10;
        y += *io.ipos++ - '0';
    }
    ++io.ipos;
    x = static_cast<T>(y);
    return io;
}

template <signed_integral T>
inline FASTIO& operator>>(FASTIO& io, T& x) noexcept {
    io.seek();
    x = 0;
    bool neg = false;
    if (*io.ipos == '-') {
        neg = true;
        ++io.ipos;
    }
    make_unsigned_t<T> u;
    io >> u;
    x = u;
    if (neg) {
        x = -x;
    }
    return io;
}

static constexpr auto LUT = [] {
    array<array<char, 4>, 10000> res;
    for (int i = 0; i < 10000; ++i) {
        res[i][0] = '0' + i / 1000;
        res[i][1] = '0' + i / 100 % 10;
        res[i][2] = '0' + i / 10 % 10;
        res[i][3] = '0' + i % 10;
    }
    return res;
}();

inline void FastWrite_(FASTIO& io, unsigned x) noexcept {
    memcpy(io.opos, &LUT[x], 4);
    io.opos += 4;
}

inline void FastWrite__(FASTIO& io, unsigned x) noexcept {
    if (x > 999) {
        memcpy(io.opos, &LUT[x], 4);
        io.opos += 4;
    } else if (x > 99) {
        memcpy(io.opos, &LUT[x * 10], 3);
        io.opos += 3;
    } else if (x > 9) {
        memcpy(io.opos, &LUT[x * 100], 2);
        io.opos += 2;
    } else {
        memcpy(io.opos, &LUT[x * 1000], 1);
        io.opos += 1;
    }
}

template <unsigned_integral T>
inline void FastWrite(FASTIO& io, T x) noexcept {
    if (x > 9999'9999'9999'9999) {
        FastWrite__(io, x / 10000 / 10000 / 10000 / 10000);
        FastWrite_(io, x / 10000 / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999'9999'9999) {
        FastWrite__(io, x / 10000 / 10000 / 10000);
        FastWrite_(io, x / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999'9999) {
        FastWrite__(io, x / 10000 / 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999) {
        FastWrite__(io, x / 10000);
        FastWrite_(io, x % 10000);
    } else {
        FastWrite__(io, x);
    }
}

template <unsigned_integral T>
inline FASTIO& operator<<(FASTIO& io, T x) noexcept {
    io.reserve(20);
    FastWrite(io, x);
    return io;
}

template <signed_integral T>
inline FASTIO& operator<<(FASTIO& io, T x) noexcept {
    io.reserve(20);
    if (x < 0) {
        *io.opos++ = '-';
        FastWrite(io, make_unsigned_t<T>(-x));
    } else {
        FastWrite(io, make_unsigned_t<T>(x));
    }
    return io;
}

template <class S, auto op, auto e, class F, auto mapping, auto composition, auto id>
struct lazy_segtree {
    lazy_segtree() : lazy_segtree(0) {}
    explicit lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    explicit lazy_segtree(const vector<S>& v) : n((int)(v.size())) {
        size = 1;
        while (size < n) size *= 2;
        log = 0;
        while (!(size & (1 << log))) log++;
        d = vector<S>(2 * size, e());
        lz = vector<F>(size, id());
        for (int i = 0; i < n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S operator[](int p) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S operator()(int l, int r) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() {
        return d[1];
    }

    void apply(int p, F f) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    int max_right(int l, auto g) {
        assert(0 <= l && l <= n);
        assert(g(e()));
        if (l == n) return n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return n;
    }

    int min_left(int r, auto g) {
        assert(0 <= r && r <= n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

   private:
    int n, size, log;
    vector<S> d;
    vector<F> lz;

    void update(int k) {
        d[k] = op(d[2 * k], d[2 * k + 1]);
    }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

#define OVERLOAD_GRAPH(_1, _2, _3, name, ...) name
#define GRAPH1(g) GRAPH3(g, n, m);
#define GRAPH2(g, m) GRAPH3(g, n, m);
#define GRAPH3(g, n, m)           \
    vector<vector<int>> g(n);     \
    for (int i = 0; i < m; i++) { \
        int u, v;                 \
        cin >> u >> v;            \
        u--;                      \
        v--;                      \
        g[u].emplace_back(v);     \
        g[v].emplace_back(u);     \
    }
#define graph(...) OVERLOAD_GRAPH(__VA_ARGS__, GRAPH3, GRAPH2, GRAPH1)(__VA_ARGS__)
using graph = vector<vector<int>>;
#define OVERLOAD_DGRAPH(_1, _2, _3, name, ...) name
#define DGRAPH1(g) DGRAPH3(g, n, m);
#define DGRAPH2(g, m) DGRAPH3(g, n, m);
#define DGRAPH3(g, n, m)          \
    vector<vector<int>> g(n);     \
    for (int i = 0; i < m; i++) { \
        int u, v;                 \
        cin >> u >> v;            \
        u--;                      \
        v--;                      \
        g[u].emplace_back(v);     \
    }
#define dgraph(...) OVERLOAD_DGRAPH(__VA_ARGS__, DGRAPH3, DGRAPH2, DGRAPH1)(__VA_ARGS__)

using ll = long long;
using lint = __int128;
using ldouble = long double;

#define endl '\n'
#define space ' '
#define ext exit(0)

#define pb push_back
#define eb emplace_back

#define MP make_pair

#define GREATER(e) e, vector<e>, greater<e>
#define IINF (int)1e9
#define INF (long long)5e18

#define RASQ pair<ll, ll>,                                                                                            \
             [](pair<ll, ll> a, pair<ll, ll> b) -> pair<ll, ll> { return {a.first + b.first, a.second + b.second}; }, \
             []() -> pair<ll, ll> { return {0ll, 0ll}; },                                                             \
             ll,                                                                                                      \
             [](ll lz, pair<ll, ll> v) { return (lz == INF ? v : make_pair(v.first + lz * v.second, v.second)); },    \
             [](ll cur, ll old) { return cur + old; },                                                                \
             []() { return 0ll; }

#define OVERLOAD_REP(_1, _2, _3, name, ...) name
#define REP1(i, n) for (auto i = 0; (i) != (n); ++(i))
#define REP2(i, l, r) for (auto i = (l); (i) != (r); ++(i))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define rrep(i, r, l) for (auto i = r; (i) != (l); --(i))
using namespace std;
#ifndef LOCAL
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2")
#endif


int main() {
    int n, q;
    cin >> n >> q;
    graph g(n);
    rep(i, n - 1) {
        int u, v;
        cin >> u >> v;
        g[u].eb(v);
        g[v].eb(u);
    }
    HLD hld(g);
    lazy_segtree<RASQ> seg(vector<pair<ll, ll>>(n, {0, 1}));
    rep(_, q) {
        int T, u, v;
        cin >> T >> u >> v;
        if (T) {
            auto [l, r] = hld.part(u);
            seg.apply(l + 1, r + 1, v);
        } else {
            vector<pair<int, int>> t = hld.route(u, v);
            ll ans = -seg[t.back().first].first;
            for (auto [l, r] : t) {
                ans += seg(l, r + 1).first;
            }
            cout << ans << endl;
        }
    }
}
accuracy: 1
time_ms: 630
memory_kb: 58908
final_rank: 16

code_snippet: #include <iterator>
#include <bits/stdc++.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <utility>
#include <vector>

using namespace std;

struct HLD {
    int n;
    vector<vector<int>> g;
    vector<int> euler, pos, dep, siz, per, root;
    vector<pair<int, pair<int, int>>> range;
    HLD(vector<vector<int>> g) : n(g.size()), g(g) {
        dep.resize(n, -1);
        per.resize(n, -1);
        pos.resize(n, -1);
        root.resize(n, -1);
        siz.resize(n, 1);
        euler.reserve(n);
        range.resize(n, {-1, {-1, -1}});
        {
            auto dfs = [&](int c, auto dfs) -> int {
                for (int i : g[c]) {
                    if (dep[i] != -1) continue;
                    per[i] = c;
                    dep[i] = dep[c] + 1;
                    siz[c] += dfs(i, dfs);
                }
                return siz[c];
            };
            per[0] = 0;
            dep[0] = 0;
            dfs(0, dfs);
        }
        {
            auto dfs = [&](int c, int r, auto dfs) -> void {
                pos[c] = euler.size();
                euler.push_back(c);
                range[c].first = pos[c];
                range[r].second.first = pos[c];
                root[c] = r;
                pair<int, int> mx(-1, -1);
                for (int i : g[c]) {
                    if (dep[i] < dep[c]) continue;
                    if (mx.second < siz[i]) {
                        mx = {i, siz[i]};
                    }
                }
                if (mx.first != -1) {
                    dfs(mx.first, r, dfs);
                }
                for (int i : g[c]) {
                    if (dep[i] < dep[c]) continue;
                    if (i != mx.first) {
                        dfs(i, i, dfs);
                    }
                }
                range[c].second.second = (int)euler.size() - 1;
            };
            dfs(0, 0, dfs);
        }
    }
    vector<pair<int, int>> route(int u, int v) {
        vector<pair<int, int>> res;
        while (root[u] != root[v]) {
            if (dep[root[v]] < dep[root[u]]) {
                res.emplace_back(make_pair(range[root[u]].first, pos[u]));
                u = per[root[u]];
            } else {
                res.emplace_back(make_pair(range[root[v]].first, pos[v]));
                v = per[root[v]];
            }
        }
        res.emplace_back(make_pair(min(pos[u], pos[v]), max(pos[u], pos[v])));
        return res;
    }
    pair<int, int> part(int u) {
        return make_pair(range[u].first, range[u].second.second);
    }
    int lca(int u, int v) {
        vector<pair<int, int>> res = route(u, v);
        return euler[res.back().first];
    }
    int size(int u) {
        return siz[u];
    }
    int depth(int u) {
        return dep[u];
    }
};


struct FASTIO {
    static constexpr int buffer_size = 1 << 20;
    char output_buffer[buffer_size];
    char *ipos, *obegin, *oend, *opos;
    struct stat st;
    explicit FASTIO() : obegin(output_buffer),
                        oend(output_buffer + buffer_size),
                        opos(output_buffer) {
        fstat(0, &st);
        ipos = (char *)mmap(nullptr, st.st_size + 64, PROT_READ, MAP_PRIVATE, 0, 0);
    }
    ~FASTIO() noexcept { this->flush(); }

    inline void seek() noexcept {
        while (*ipos <= ' ') [[unlikely]] {
            ++ipos;
        }
    }

    inline void flush() noexcept {
        ignore = ::write(1, obegin, opos - obegin);
        opos = obegin;
    }

    inline void reserve(int x) noexcept {
        if (oend - opos < x) [[unlikely]] {
            flush();
        }
    }
} FIO;

#define cin FIO
#define cout FIO

inline FASTIO& operator<<(FASTIO& io, char c) noexcept {
    io.reserve(1);
    *io.opos++ = c;
    return io;
}

template <unsigned_integral T>
inline FASTIO& operator>>(FASTIO& io, T& x) noexcept {
    io.seek();
    common_type_t<T, uint64_t> y = 0;
    while (true) {
        uint64_t v;
        memcpy(&v, io.ipos, 8);
        if ((v -= 0x3030303030303030) & 0x8080808080808080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff00ff00ff00ff;
        v = (v * 100 + (v >> 16)) & 0xffff0000ffff;
        v = (v * 10000 + (v >> 32)) & 0xffffffff;
        y = 100000000 * y + v;
        io.ipos += 8;
    }
    while (true) {
        uint32_t v;
        memcpy(&v, io.ipos, 4);
        if ((v -= 0x30303030) & 0x80808080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff00ff;
        v = (v * 100 + (v >> 16)) & 0xffff;
        y = 10000 * y + v;
        io.ipos += 4;
    }
    while (true) {
        uint16_t v;
        memcpy(&v, io.ipos, 2);
        if ((v -= 0x3030) & 0x8080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff;
        y = 100 * y + v;
        io.ipos += 2;
    }
    while (' ' < *io.ipos) {
        y *= 10;
        y += *io.ipos++ - '0';
    }
    ++io.ipos;
    x = static_cast<T>(y);
    return io;
}

template <signed_integral T>
inline FASTIO& operator>>(FASTIO& io, T& x) noexcept {
    io.seek();
    x = 0;
    bool neg = false;
    if (*io.ipos == '-') {
        neg = true;
        ++io.ipos;
    }
    make_unsigned_t<T> u;
    io >> u;
    x = u;
    if (neg) {
        x = -x;
    }
    return io;
}

static constexpr auto LUT = [] {
    array<array<char, 4>, 10000> res;
    for (int i = 0; i < 10000; ++i) {
        res[i][0] = '0' + i / 1000;
        res[i][1] = '0' + i / 100 % 10;
        res[i][2] = '0' + i / 10 % 10;
        res[i][3] = '0' + i % 10;
    }
    return res;
}();

inline void FastWrite_(FASTIO& io, unsigned x) noexcept {
    memcpy(io.opos, &LUT[x], 4);
    io.opos += 4;
}

inline void FastWrite__(FASTIO& io, unsigned x) noexcept {
    if (x > 999) {
        memcpy(io.opos, &LUT[x], 4);
        io.opos += 4;
    } else if (x > 99) {
        memcpy(io.opos, &LUT[x * 10], 3);
        io.opos += 3;
    } else if (x > 9) {
        memcpy(io.opos, &LUT[x * 100], 2);
        io.opos += 2;
    } else {
        memcpy(io.opos, &LUT[x * 1000], 1);
        io.opos += 1;
    }
}

template <unsigned_integral T>
inline void FastWrite(FASTIO& io, T x) noexcept {
    if (x > 9999'9999'9999'9999) {
        FastWrite__(io, x / 10000 / 10000 / 10000 / 10000);
        FastWrite_(io, x / 10000 / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999'9999'9999) {
        FastWrite__(io, x / 10000 / 10000 / 10000);
        FastWrite_(io, x / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999'9999) {
        FastWrite__(io, x / 10000 / 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999) {
        FastWrite__(io, x / 10000);
        FastWrite_(io, x % 10000);
    } else {
        FastWrite__(io, x);
    }
}

template <unsigned_integral T>
inline FASTIO& operator<<(FASTIO& io, T x) noexcept {
    io.reserve(20);
    FastWrite(io, x);
    return io;
}

template <signed_integral T>
inline FASTIO& operator<<(FASTIO& io, T x) noexcept {
    io.reserve(20);
    if (x < 0) {
        *io.opos++ = '-';
        FastWrite(io, make_unsigned_t<T>(-x));
    } else {
        FastWrite(io, make_unsigned_t<T>(x));
    }
    return io;
}

template <class S, auto op, auto e, class F, auto mapping, auto composition, auto id>
struct lazy_segtree {
    lazy_segtree() : lazy_segtree(0) {}
    explicit lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    explicit lazy_segtree(const vector<S>& v) : n((int)(v.size())) {
        size = 1;
        while (size < n) size *= 2;
        log = 0;
        while (!(size & (1 << log))) log++;
        d = vector<S>(2 * size, e());
        lz = vector<F>(size, id());
        for (int i = 0; i < n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S operator[](int p) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S operator()(int l, int r) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() {
        return d[1];
    }

    void apply(int p, F f) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    int max_right(int l, auto g) {
        assert(0 <= l && l <= n);
        assert(g(e()));
        if (l == n) return n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return n;
    }

    int min_left(int r, auto g) {
        assert(0 <= r && r <= n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

   private:
    int n, size, log;
    vector<S> d;
    vector<F> lz;

    void update(int k) {
        d[k] = op(d[2 * k], d[2 * k + 1]);
    }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

#define OVERLOAD_GRAPH(_1, _2, _3, name, ...) name
#define GRAPH1(g) GRAPH3(g, n, m);
#define GRAPH2(g, m) GRAPH3(g, n, m);
#define GRAPH3(g, n, m)           \
    vector<vector<int>> g(n);     \
    for (int i = 0; i < m; i++) { \
        int u, v;                 \
        cin >> u >> v;            \
        u--;                      \
        v--;                      \
        g[u].emplace_back(v);     \
        g[v].emplace_back(u);     \
    }
#define graph(...) OVERLOAD_GRAPH(__VA_ARGS__, GRAPH3, GRAPH2, GRAPH1)(__VA_ARGS__)
using graph = vector<vector<int>>;
#define OVERLOAD_DGRAPH(_1, _2, _3, name, ...) name
#define DGRAPH1(g) DGRAPH3(g, n, m);
#define DGRAPH2(g, m) DGRAPH3(g, n, m);
#define DGRAPH3(g, n, m)          \
    vector<vector<int>> g(n);     \
    for (int i = 0; i < m; i++) { \
        int u, v;                 \
        cin >> u >> v;            \
        u--;                      \
        v--;                      \
        g[u].emplace_back(v);     \
    }
#define dgraph(...) OVERLOAD_DGRAPH(__VA_ARGS__, DGRAPH3, DGRAPH2, DGRAPH1)(__VA_ARGS__)

using ll = long long;
using lint = __int128;
using ldouble = long double;

#define endl '\n'
#define space ' '
#define ext exit(0)

#define pb push_back
#define eb emplace_back

#define MP make_pair

#define GREATER(e) e, vector<e>, greater<e>
#define IINF (int)1e9
#define INF (long long)5e18

#define RASQ pair<ll, ll>,                                                                                            \
             [](pair<ll, ll> a, pair<ll, ll> b) -> pair<ll, ll> { return {a.first + b.first, a.second + b.second}; }, \
             []() -> pair<ll, ll> { return {0ll, 0ll}; },                                                             \
             ll,                                                                                                      \
             [](ll lz, pair<ll, ll> v) { return (lz == INF ? v : make_pair(v.first + lz * v.second, v.second)); },    \
             [](ll cur, ll old) { return cur + old; },                                                                \
             []() { return 0ll; }

#define OVERLOAD_REP(_1, _2, _3, name, ...) name
#define REP1(i, n) for (auto i = 0; (i) != (n); ++(i))
#define REP2(i, l, r) for (auto i = (l); (i) != (r); ++(i))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define rrep(i, r, l) for (auto i = r; (i) != (l); --(i))
using namespace std;
#ifndef LOCAL
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2")
#endif


int main() {
    int n, q;
    cin >> n >> q;
    graph g(n);
    rep(i, n - 1) {
        int u, v;
        cin >> u >> v;
        g[u].eb(v);
        g[v].eb(u);
    }
    HLD hld(g);
    lazy_segtree<RASQ> seg(vector<pair<ll, ll>>(n, {0, 1}));
    rep(_, q) {
        int T, u, v;
        cin >> T >> u >> v;
        if (T) {
            auto [l, r] = hld.part(u);
            seg.apply(l + 1, r + 1, v);
        } else {
            vector<pair<int, int>> t = hld.route(u, v);
            int ans = -seg[t.back().first].first;
            for (auto [l, r] : t) {
                ans += seg(l, r + 1).first;
            }
            cout << ans << endl;
        }
    }
}
accuracy: 0.47368421052631576
time_ms: 160
memory_kb: 49756
final_rank: 20

code_snippet: #include <iterator>
#include <bits/stdc++.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <utility>
#include <vector>

using namespace std;

struct HLD {
    int n;
    vector<vector<int>> g;
    vector<int> euler, pos, dep, siz, per, root;
    vector<pair<int, pair<int, int>>> range;
    HLD(vector<vector<int>> g) : n(g.size()), g(g) {
        dep.resize(n, -1);
        per.resize(n, -1);
        pos.resize(n, -1);
        root.resize(n, -1);
        siz.resize(n, 1);
        euler.reserve(n);
        range.resize(n, {-1, {-1, -1}});
        {
            auto dfs = [&](int c, auto dfs) -> int {
                for (int i : g[c]) {
                    if (dep[i] != -1) continue;
                    per[i] = c;
                    dep[i] = dep[c] + 1;
                    siz[c] += dfs(i, dfs);
                }
                return siz[c];
            };
            per[0] = 0;
            dep[0] = 0;
            dfs(0, dfs);
        }
        {
            auto dfs = [&](int c, int r, auto dfs) -> void {
                pos[c] = euler.size();
                euler.push_back(c);
                range[c].first = pos[c];
                range[r].second.first = pos[c];
                root[c] = r;
                pair<int, int> mx(-1, -1);
                for (int i : g[c]) {
                    if (dep[i] < dep[c]) continue;
                    if (mx.second < siz[i]) {
                        mx = {i, siz[i]};
                    }
                }
                if (mx.first != -1) {
                    dfs(mx.first, r, dfs);
                }
                for (int i : g[c]) {
                    if (dep[i] < dep[c]) continue;
                    if (i != mx.first) {
                        dfs(i, i, dfs);
                    }
                }
                range[c].second.second = (int)euler.size() - 1;
            };
            dfs(0, 0, dfs);
        }
    }
    vector<pair<int, int>> route(int u, int v) {
        vector<pair<int, int>> res;
        while (root[u] != root[v]) {
            if (dep[root[v]] < dep[root[u]]) {
                res.emplace_back(make_pair(range[root[u]].first, pos[u]));
                u = per[root[u]];
            } else {
                res.emplace_back(make_pair(range[root[v]].first, pos[v]));
                v = per[root[v]];
            }
        }
        res.emplace_back(make_pair(min(pos[u], pos[v]), max(pos[u], pos[v])));
        return res;
    }
    pair<int, int> part(int u) {
        return make_pair(range[u].first, range[u].second.second);
    }
    int lca(int u, int v) {
        vector<pair<int, int>> res = route(u, v);
        return euler[res.back().first];
    }
    int size(int u) {
        return siz[u];
    }
    int depth(int u) {
        return dep[u];
    }
};


struct FASTIO {
    static constexpr int buffer_size = 1 << 20;
    char output_buffer[buffer_size];
    char *ipos, *obegin, *oend, *opos;
    struct stat st;
    explicit FASTIO() : obegin(output_buffer),
                        oend(output_buffer + buffer_size),
                        opos(output_buffer) {
        fstat(0, &st);
        ipos = (char *)mmap(nullptr, st.st_size + 64, PROT_READ, MAP_PRIVATE, 0, 0);
    }
    ~FASTIO() noexcept { this->flush(); }

    inline void seek() noexcept {
        while (*ipos <= ' ') {
            ++ipos;
        }
    }

    inline void flush() noexcept {
        ignore = ::write(1, obegin, opos - obegin);
        opos = obegin;
    }

    inline void reserve(int x) noexcept {
        if (oend - opos < x) [[unlikely]] {
            flush();
        }
    }
} FIO;

#define cin FIO
#define cout FIO

inline FASTIO& operator<<(FASTIO& io, char c) noexcept {
    io.reserve(1);
    *io.opos++ = c;
    return io;
}

template <unsigned_integral T>
inline FASTIO& operator>>(FASTIO& io, T& x) noexcept {
    io.seek();
    common_type_t<T, uint64_t> y = 0;
    while (true) {
        uint64_t v;
        memcpy(&v, io.ipos, 8);
        if ((v -= 0x3030303030303030) & 0x8080808080808080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff00ff00ff00ff;
        v = (v * 100 + (v >> 16)) & 0xffff0000ffff;
        v = (v * 10000 + (v >> 32)) & 0xffffffff;
        y = 100000000 * y + v;
        io.ipos += 8;
    }
    while (true) {
        uint32_t v;
        memcpy(&v, io.ipos, 4);
        if ((v -= 0x30303030) & 0x80808080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff00ff;
        v = (v * 100 + (v >> 16)) & 0xffff;
        y = 10000 * y + v;
        io.ipos += 4;
    }
    while (true) {
        uint16_t v;
        memcpy(&v, io.ipos, 2);
        if ((v -= 0x3030) & 0x8080) {
            break;
        }
        v = (v * 10 + (v >> 8)) & 0xff;
        y = 100 * y + v;
        io.ipos += 2;
    }
    while (' ' < *io.ipos) {
        y *= 10;
        y += *io.ipos++ - '0';
    }
    ++io.ipos;
    x = static_cast<T>(y);
    return io;
}

template <signed_integral T>
inline FASTIO& operator>>(FASTIO& io, T& x) noexcept {
    io.seek();
    x = 0;
    bool neg = false;
    if (*io.ipos == '-') {
        neg = true;
        ++io.ipos;
    }
    make_unsigned_t<T> u;
    io >> u;
    x = u;
    if (neg) {
        x = -x;
    }
    return io;
}

static constexpr auto LUT = [] {
    array<array<char, 4>, 10000> res;
    for (int i = 0; i < 10000; ++i) {
        res[i][0] = '0' + i / 1000;
        res[i][1] = '0' + i / 100 % 10;
        res[i][2] = '0' + i / 10 % 10;
        res[i][3] = '0' + i % 10;
    }
    return res;
}();

inline void FastWrite_(FASTIO& io, unsigned x) noexcept {
    memcpy(io.opos, &LUT[x], 4);
    io.opos += 4;
}

inline void FastWrite__(FASTIO& io, unsigned x) noexcept {
    if (x > 999) {
        memcpy(io.opos, &LUT[x], 4);
        io.opos += 4;
    } else if (x > 99) {
        memcpy(io.opos, &LUT[x * 10], 3);
        io.opos += 3;
    } else if (x > 9) {
        memcpy(io.opos, &LUT[x * 100], 2);
        io.opos += 2;
    } else {
        memcpy(io.opos, &LUT[x * 1000], 1);
        io.opos += 1;
    }
}

template <unsigned_integral T>
inline void FastWrite(FASTIO& io, T x) noexcept {
    if (x > 9999'9999'9999'9999) {
        FastWrite__(io, x / 10000 / 10000 / 10000 / 10000);
        FastWrite_(io, x / 10000 / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999'9999'9999) {
        FastWrite__(io, x / 10000 / 10000 / 10000);
        FastWrite_(io, x / 10000 / 10000 % 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999'9999) {
        FastWrite__(io, x / 10000 / 10000);
        FastWrite_(io, x / 10000 % 10000);
        FastWrite_(io, x % 10000);
    } else if (x > 9999) {
        FastWrite__(io, x / 10000);
        FastWrite_(io, x % 10000);
    } else {
        FastWrite__(io, x);
    }
}

template <unsigned_integral T>
inline FASTIO& operator<<(FASTIO& io, T x) noexcept {
    io.reserve(20);
    FastWrite(io, x);
    return io;
}

template <signed_integral T>
inline FASTIO& operator<<(FASTIO& io, T x) noexcept {
    io.reserve(20);
    if (x < 0) {
        *io.opos++ = '-';
        FastWrite(io, make_unsigned_t<T>(-x));
    } else {
        FastWrite(io, make_unsigned_t<T>(x));
    }
    return io;
}

template <class S, auto op, auto e, class F, auto mapping, auto composition, auto id>
struct lazy_segtree {
    lazy_segtree() : lazy_segtree(0) {}
    explicit lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    explicit lazy_segtree(const vector<S>& v) : n((int)(v.size())) {
        size = 1;
        while (size < n) size *= 2;
        log = 0;
        while (!(size & (1 << log))) log++;
        d = vector<S>(2 * size, e());
        lz = vector<F>(size, id());
        for (int i = 0; i < n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S operator[](int p) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S operator()(int l, int r) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() {
        return d[1];
    }

    void apply(int p, F f) {
        assert(0 <= p && p < n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    int max_right(int l, auto g) {
        assert(0 <= l && l <= n);
        assert(g(e()));
        if (l == n) return n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return n;
    }

    int min_left(int r, auto g) {
        assert(0 <= r && r <= n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

   private:
    int n, size, log;
    vector<S> d;
    vector<F> lz;

    void update(int k) {
        d[k] = op(d[2 * k], d[2 * k + 1]);
    }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

using ll = long long;
using lint = __int128;
using ldouble = long double;

#define endl '\n'
#define space ' '
#define ext exit(0)

#define pb push_back
#define eb emplace_back

#define MP make_pair

#define GREATER(e) e, vector<e>, greater<e>
#define IINF (int)1e9
#define INF (long long)5e18

#define RASQ pair<ll, ll>,                                                                                            \
             [](pair<ll, ll> a, pair<ll, ll> b) -> pair<ll, ll> { return {a.first + b.first, a.second + b.second}; }, \
             []() -> pair<ll, ll> { return {0ll, 0ll}; },                                                             \
             ll,                                                                                                      \
             [](ll lz, pair<ll, ll> v) { return (lz == INF ? v : make_pair(v.first + lz * v.second, v.second)); },    \
             [](ll cur, ll old) { return cur + old; },                                                                \
             []() { return 0ll; }

#define OVERLOAD_REP(_1, _2, _3, name, ...) name
#define REP1(i, n) for (auto i = 0; (i) != (n); ++(i))
#define REP2(i, l, r) for (auto i = (l); (i) != (r); ++(i))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define rrep(i, r, l) for (auto i = r; (i) != (l); --(i))
using namespace std;
#ifndef LOCAL
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2")
#endif


int main() {
    int n, Q;
    cin >> n >> Q;
    vector<vector<int>> g(n);
    rep(i, n - 1) {
        int u, v;
        cin >> u >> v;
        g[u].eb(v);
        g[v].eb(u);
    }
    HLD hld(g);
    lazy_segtree<RASQ> seg(vector<pair<ll, ll>>(n, MP(0, 1)));
    rep(_, Q) {
        short T;
        cin >> T;
        if (T == 0) {
            ll u, v;
            cin >> u >> v;
            vector<pair<int, int>> t = hld.route(u, v);
            ll ans = -seg[t.back().first].first;
            for (auto [l, r] : t) {
                ans += seg(l, r + 1).first;
            }
            cout << ans << endl;
        } else {
            ll v, x;
            cin >> v >> x;
            auto [l, r] = hld.part(v);
            seg.apply(l + 1, r + 1, x);
        }
    }
}
accuracy: 1
time_ms: 640
memory_kb: 58984
final_rank: 17

code_snippet: #ifdef syssys
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;

using uint = unsigned;
using ull = unsigned long long;
using ll = long long;
using ld = long double;
#define el '\n'
#define all(x) begin(x), end(x)
#define initv2(t,a,...) a, vector<t>(__VA_ARGS__)
#define initv3(t,a,b,...) a, vector<vector<t>>(b, vector<t>(__VA_ARGS__))
#define pair(a,b) pair<a, b>
#define vec vector
#define elif else if
#define pri_q priority_queue
#ifndef syssys
struct fast_io{fast_io(){ios::sync_with_stdio(0); cin.tie(0);}} _fast_io;
#endif

struct FIstream{
    #ifndef syssys
    #define fread fread_unlocked
    #endif
    
    static const unsigned SIZ = 1 << 17;
    char buf[SIZ], *p1 = buf, *p2 = buf;
    
    inline char _getchar(){
        if(p1 == p2){
            p2 = (p1 = buf) + fread(buf, 1, SIZ, stdin);
            if(p1 == p2) return EOF;
        }
        return *p1++;
    }
    
    inline char ignore_space(){
        char c;
        while((c = _getchar()) <= 0x20);
        return c;
    }
    
    template<typename T>
    inline void _read(T& res){
        T x = 0, f = 1;
        char c = ignore_space();
        if(c == '-'){
            f = -1;
            c = _getchar();
        }
        while('0' <= c && c <= '9'){
            x = x*10 + (c-'0');
            c = _getchar();
        }
        res = x*f;
    }
    
    template<typename T>
    inline FIstream& operator>>(T& x){_read(x); return *this;}
    inline FIstream& operator>>(char& x){x = ignore_space(); return *this;}
    inline FIstream& operator>>(string& x){
        string().swap(x);
        char c = ignore_space();
        while(c > 0x20){
            x.push_back(c);
            c = _getchar();
        }
        return *this;
    }
    #ifndef syssys
    #undef fread
    #endif
} _cin;
#define cin _cin
#define istream FIstream

struct Pre{
    char num[10000][4];
    constexpr Pre():num(){
        for(int i = 0; i < 10000; i++){
            int x = i;
            for(int j = 3; j >= 0; j--){
                num[i][j] = x%10 + '0';
                x /= 10;
            }
        }
    }
} constexpr pre;

struct FOstream{
    #ifndef syssys
    #define fwrite fwrite_unlocked
    #endif
        
    static const unsigned SIZ = 1 << 17;
    char buf[SIZ], *p1 = buf, *p2 = buf+SIZ;
        
    inline void _write(){
        fwrite(buf, 1, p1-buf, stdout);
        p1 = buf;
    }
        
    inline void _putchar(char c){
        if(p1 == p2){
            fwrite(buf, 1, p1 - buf, stdout);
            p1 = buf;
        }
        *p1++ = c;
    }
        
    template<typename T>
    void _write_i(T x){
        char num[100], *idxp = num+100;
        if(x < 0){
            _putchar('-');
            x = -x;
        }
        if(p1 - buf < 100) _write();
        while(x >= 10000){
            idxp -= 4;
            memcpy(idxp, pre.num[x%10000], 4);
            x /= 10000;
        }
        if(x >= 1000){
            memcpy(p1, pre.num[x], 4);
            p1 += 4;
        } else if(x >= 100){
            memcpy(p1, pre.num[x]+1, 3);
            p1 += 3;
        } else if(x >= 10){
            memcpy(p1, pre.num[x]+2, 2);
            p1 += 2;
        } else *p1++ = x+'0';
        memcpy(p1, idxp, num+100 - idxp);
        p1 += num+100 - idxp;
    }
        
    template<typename T>
    FOstream& operator<<(T x){
        if constexpr(is_same_v<T, char>){
            _putchar(x);
        } else if constexpr(is_same_v<decay_t<T>, const char*> || is_same_v<decay_t<T>, char*>){
            while(*x) _putchar(*x++);
        } else if constexpr(is_integral_v<T> || is_same_v<T, __int128>){
            _write_i(x);
        } else if constexpr(is_same_v<T, float> || is_same_v<T, double>){
            char _b[100];
            snprintf(_b, sizeof(_b), "%.*f", 15, x);
            *this << _b;
        } else if constexpr(is_same_v<T, long double>){
            char _b[100];
            snprintf(_b, sizeof(_b), "%.*Lf", 15, x);
            *this << _b;
        } else assert(0);
        return *this;
    }
    FOstream& operator<<(const string& x){
        for(char i : x) _putchar(i);
        return *this;
    }
        
    ~FOstream(){
        if(p1 != buf){
            fwrite(buf, 1, p1 - buf, stdout);
        }
    }
        
    #ifndef syssys
    #undef fwrite
    #endif
} _cout;
#define cout _cout
#define ostream FOstream

namespace Myb{
    constexpr long long LLINF = 1ll<<62;
    constexpr int INF = 1<<30;
    
    template<typename T, typename U> istream& operator>>(istream& ist, pair<T, U>& p) {cin >> p.first >> p.second; return ist;}
    template<typename T> istream& operator>>(istream& ist, vector<T>& v) {for(T& i : v) cin >> i; return ist;}
    istream& operator>>(istream& ist, _Float128& x) {long double n; cin >> n; x = n; return ist;}
    void read_d_graph(vector<vector<pair<long long, int>>>& v, int m, int num = -1){
        int a, b; long long c;
        for(int _ = 0; _ < m; _++){
            cin >> a >> b >> c;
            a += num; b += num;
            v[a].emplace_back(c, b);
        }
    }
    void read_d_graph(vector<vector<int>>& v, int m, int num = -1){
        int a, b;
        for(int _ = 0; _ < m; _++){
            cin >> a >> b;
            a += num; b += num;
            v[a].emplace_back(b);
        }
    }
    void read_ud_graph(vector<vector<pair<long long, int>>>& v, int m, int num = -1){
        int a, b; long long c;
        for(int _ = 0; _ < m; _++){
            cin >> a >> b >> c;
            a += num; b += num;
            v[a].emplace_back(c, b);
            v[b].emplace_back(c, a);
        }
    }
    void read_ud_graph(vector<vector<int>>& v, int m, int num = -1){
        int a, b;
        for(int _ = 0; _ < m; _++){
            cin >> a >> b;
            a += num; b += num;
            v[a].emplace_back(b);
            v[b].emplace_back(a);
        }
    }
    template<typename T> void read_multi() {}
    template<typename T, typename... U> void read_multi(int n, vector<T>& v, U&&... args){
        if(n < ssize(v)) {cin >> v[n]; read_multi(args..., n+1, v);}
    }
    template<typename T, typename... U> void read_multi(vector<T>& v, U&&... args) {read_multi(args..., 0, v);}
    string input() {string res; cin >> res; return res;}
    long long inputl() {long long res; cin >> res; return res;}
    template<typename T, typename U> ostream& operator<<(ostream& ost, const pair<T, U> p) {cerr << '{'; ost << p.first << ' ' << p.second; cerr << '}'; return ost;}
    template<typename T> ostream& operator<<(ostream& ost, const vector<T>& v) {for(int i = 0; i < ssize(v); i++) {ost << (i ? " " : "") << v[i];} return ost;}
    template<typename T> ostream& operator<<(ostream& ost, const vector<vector<T>>& v) {for(int i = 0; i < ssize(v); i++) {ost << (i ? "\n" : "") << v[i];} return ost;}
    
    long long add_each(long long n) {return n;}
    template<typename T, typename... U> void add_each(long long n, vector<T>& v, U&... args){
        for(auto& i : v) i += n; add_each(n, args...);
    }
    
    template<typename T, typename U> inline bool chmin(T& a, U b) {if(a > b){a = b; return true;} return false;}
    template<typename T, typename U> inline bool chmax(T& a, U b) {if(a < b){a = b; return true;} return false;}
    template<typename T> inline T minv(const vector<T>& v) {return *min_element(v.begin(), v.end());}
    template<typename T> inline T maxv(const vector<T>& v) {return *max_element(v.begin(), v.end());}
    
    long long power(long long val, long long num, long long mod = 0){
        assert(mod >= 0); assert(num >= 0);
        long long res = 1;
        if(mod){
            val %= mod;
            while(num){
                if(num&1) res = (res*val)%mod;
                val = (val*val)%mod;
                num >>= 1;
            }
        } else {
            while(num){
                if(num&1) res = (res*val);
                val = (val*val);
                num >>= 1;
            }
        }
        return res;
    }
    
    long long comb(long long N, long long K, int mod = 0){
        constexpr int COMBSIZ = 200000;
        assert(mod >= 0);
        if(N < K || K < 0) return 0;
        if(mod != 0){
            assert(N <= COMBSIZ);
            static vector<long long> combf(COMBSIZ+9, -1);
            if(combf[0] == -1){
                combf[0] = 1;
                for(long long i = 1; i <= COMBSIZ; i++) combf[i] = (combf[i-1]*i)%mod;
            }
            return (combf[N]*power((combf[N-K]*combf[K])%mod, mod-2, mod))%mod;
        } else {
            long long a=1, b=1;
            K = min(K, N-K);
            for(long long i = N; i > N-K; i--) a *= i;
            for(long long i = 2; i <= K; i++) b *= i;
            return a/b;
        }
    }
} using namespace Myb;

#if __has_include(<atcoder/modint>)
#include <atcoder/modint>
using namespace atcoder;
using mint9 = modint998244353;
using mint1 = modint1000000007;
ostream& operator<<(ostream& ost, const mint1& x) {ost << x.val(); return ost;}
ostream& operator<<(ostream& ost, const mint9& x) {ost << x.val(); return ost;}
#endif
/*vvv^vvvv^vvvvv^^^^^^^^^vv^^^^^^vvvvv^^^vvvvv^^^^^^^^vvvvvvvvv^^^^^^^vvvvvvvvv^^^vv^^^vvvvvvvv^^^^vvvvvv^^vvvvvv^^^^vvv^^^vvvvvvvv^^^vv^^^^^^^vvvvvvvvv^^^^^_^^vvvvvvvv^^^^^^^^vvvv^vvvvvvvvv^^^^^^^v*/

#ifndef ATCODER_LAZYSEGTREE_HPP
#define ATCODER_LAZYSEGTREE_HPP 1

#include <algorithm>
#include <cassert>
#include <functional>
#include <vector>

#ifndef ATCODER_INTERNAL_BITOP_HPP
#define ATCODER_INTERNAL_BITOP_HPP 1

#ifdef _MSC_VER
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace atcoder {

namespace internal {

#if __cplusplus >= 202002L

using std::bit_ceil;

#else

// @return same with std::bit::bit_ceil
unsigned int bit_ceil(unsigned int n) {
    unsigned int x = 1;
    while (x < (unsigned int)(n)) x *= 2;
    return x;
}

#endif

// @param n `1 <= n`
// @return same with std::bit::countr_zero
int countr_zero(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

// @param n `1 <= n`
// @return same with std::bit::countr_zero
constexpr int countr_zero_constexpr(unsigned int n) {
    int x = 0;
    while (!(n & (1 << x))) x++;
    return x;
}

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_INTERNAL_BITOP_HPP

namespace atcoder {

#if __cplusplus >= 201703L

template <class S,
          auto op,
          auto e,
          class F,
          auto mapping,
          auto composition,
          auto id>
struct lazy_segtree {
    static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                  "op must work as S(S, S)");
    static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                  "e must work as S()");
    static_assert(
        std::is_convertible_v<decltype(mapping), std::function<S(F, S)>>,
        "mapping must work as S(F, S)");
    static_assert(
        std::is_convertible_v<decltype(composition), std::function<F(F, F)>>,
        "composition must work as F(F, F)");
    static_assert(std::is_convertible_v<decltype(id), std::function<F()>>,
                  "id must work as F()");

#else

template <class S,
          S (*op)(S, S),
          S (*e)(),
          class F,
          S (*mapping)(F, S),
          F (*composition)(F, F),
          F (*id)()>
struct lazy_segtree {

#endif

  public:
    lazy_segtree() : lazy_segtree(0) {}
    explicit lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    explicit lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        size = (int)internal::bit_ceil((unsigned int)(_n));
        log = internal::countr_zero((unsigned int)size);
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e()));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

}  // namespace atcoder

#endif  // ATCODER_LAZYSEGTREE_HPP

#ifdef ATCODER_LAZYSEGTREE_HPP
template<typename S, auto op, auto e, typename F, auto mapping, auto composition, auto id>
#else
template<typename S, auto op, auto e>
#endif
struct hld_tree{
    #ifdef ATCODER_LAZYSEGTREE_HPP
    using node_type = atcoder::lazy_segtree<S, op, e, F, mapping, composition, id>;
    #else
    using node_type = segtree<S, op, e>;
    #endif
    int n;
    vector<int> dep, in, out, head, par;
    node_type node;
    
    hld_tree(const vector<vector<pair<S, int>>>& g, int r = 0):
        n(g.size()), dep(n), in(n), out(n), head(n), par(n), node(n){
            assert(0 <= r && r < n);
            vector<int> sub_siz(n);
            auto dfs1 = [&](auto&& self, int pos, int pre)->void {
                par[pos] = pre; sub_siz[pos] = 1;
                
                for(const auto& [w, nex] : g[pos]){
                    if(nex == pre) continue;
                    self(self, nex, pos);
                    sub_siz[pos] += sub_siz[nex];
                }
            }; dfs1(dfs1, r, -1);
            
            int node_siz = 0;
            auto dfs2 = [&](auto self, int pos, int pre, int d, int h)->void {
                dep[pos] = d; head[pos] = h; in[pos] = node_siz++;
                
                int h_pos = -1;
                for(const auto& [w, nex] : g[pos]){
                    if(nex == pre) continue;
                    if(h_pos == -1 || sub_siz[h_pos] < sub_siz[nex]){
                        h_pos = nex;
                    }
                }
                
                if(h_pos != -1) self(self, h_pos, pos, d, h);
                
                for(const auto& [w, nex] : g[pos]){
                    if(nex == pre || nex == h_pos) continue;
                    self(self, nex, pos, d+1, nex);
                }
                out[pos] = node_siz;
            }; dfs2(dfs2, r, -1, 0, r);
            
            for(int i = 0; i < n; i++){
                for(const auto& [w, to] : g[i]){
                    if(i == par[to]) node.set(in[to], w);
                }
            }
        }
    
    void set(int l, int r, const S& x){
        assert(0 <= l && 0 <= r && l < n && r < n);
        if(par[r] != l) swap(l, r);
        assert(par[r] == l);
        node.set(in[r], x);
    }
    
    S prod(int l, int r){
        assert(0 <= l && 0 <= r && l < n && r < n);
        S ans = e();
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                ans = op(ans, node.prod(in[head[l]], in[l]+1));
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                if(l != r) ans = op(ans, node.prod(in[l]+1, in[r]+1));
                return ans;
            }
        }
    }
    
    //要修正
    S prod(int r){
        assert(0 <= r && r < n);
        return node.prod(in[r]+1, out[r]);
    }
    
    int lca(int l, int r){
        assert(0 <= l && 0 <= r && l < n && r < n);
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                return l;
            }
        }
    }
    
    int dist(int l, int r){
        assert(0 <= l && 0 <= r && l < n && r < n);
        int d = 0;
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                d += in[l] - in[head[l]] + 1;
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                d += in[r] - in[l];
                return d;
            }
        }
    }
    
    #ifdef ATCODER_LAZYSEGTREE_HPP
    void apply(int l, int r, const F& x){
        while(true){
            if(dep[l] < dep[r]) swap(l, r);
            if(dep[l] != dep[r] || head[l] != head[r]){
                node.apply(in[head[l]], in[l]+1, x);
                l = par[head[l]];
            } else {
                if(in[l] > in[r]) swap(l, r);
                node.apply(in[l]+1, in[r]+1, x);
                break;
            }
        }
    }
    
    void apply(int r, const F& x){
        node.apply(in[r]+1, out[r], x);
    }
    #endif
};

struct S{
    long long value;
    int size;
};
using F = long long;

S op(S a, S b){ return {a.value+b.value, a.size+b.size}; }
S e(){ return {0, 0}; }
S mapping(F f, S x){ return {x.value + f*x.size, x.size}; }
F composition(F f, F g){ return f+g; }
F id(){ return 0; }

signed main(){
    int n, q;
    cin >> n >> q;
    vec<vec<pair<S, int>>> G(n);
    for(int i = 0; i < n-1; i++){
        int u, v;
        cin >> u >> v;
        G[u].emplace_back(S{0, 1}, v);
        G[v].emplace_back(S{0, 1}, u);
    }
    hld_tree<S, op, e, F, mapping, composition, id> tree(G);
    
    while(q--){
        int t, v, x;
        cin >> t >> v >> x;
        if(t == 0){
            cout << tree.prod(v, x).value << el;
        } else {
            tree.apply(v, x);
        }
    }
}
accuracy: 1
time_ms: 240
memory_kb: 46240
final_rank: 7

code_snippet: // AOJ #2667
// Tree 2025.2.4

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

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(ll n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}
 
// Fenwick Tree （区間更新・点取得）
struct Fenw {
    int n;
    vector<ll> tree;
    Fenw(int n): n(n), tree(n+1, 0) {}
    void update(int i, ll delta) {
        for(; i <= n; i += i & -i)
            tree[i] += delta;
    }
    ll query(int i) {
        ll s = 0;
        for(; i; i -= i & -i)
            s += tree[i];
        return s;
    }
    void range_update(int l, int r, ll delta) {
        if(l > r) return;
        update(l, delta);
        update(r+1, -delta);
    }
};
 
const int NMAX = 150000;
int N, Q;
vector<int> adj[NMAX+1];
int tin[NMAX+1], tout[NMAX+1], depthArr[NMAX+1];
int timer = 0;
int parent[20][NMAX+1];
 
void dfs(int u, int p, int d) {
    depthArr[u] = d;
    parent[0][u] = p;
    tin[u] = ++timer;
    for (int v : adj[u]) {
        if(v == p) continue;
        dfs(v, u, d+1);
    }
    tout[u] = timer;
}
 
void initLCA() {
    for (int k = 0; k+1 < 20; k++){
        for (int u = 0; u < N; u++){
            int mid = parent[k][u];
            parent[k+1][u] = (mid == -1 ? -1 : parent[k][mid]);
        }
    }
}
 
int lca(int u, int v) {
    if(depthArr[u] < depthArr[v]) swap(u,v);
    int d = depthArr[u] - depthArr[v];
    for (int k = 0; d; k++){
        if(d & 1) u = parent[k][u];
        d >>= 1;
    }
    if(u == v) return u;
    for (int k = 19; k >= 0; k--){
        if(parent[k][u] != parent[k][v]){
            u = parent[k][u];
            v = parent[k][v];
        }
    }
    return parent[0][u];
}
 
int main(){
    N = Cin(), Q = Cin();
    for (int i = 0; i < N-1; i++){
        int a = Cin(), b = Cin();
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    
    dfs(0, -1, 0);
    initLCA();
    
    Fenw BIT1(N), BIT2(N);
    
    for (int i = 0; i < Q; i++){
        int t;
        cin >> t;
        if(t == 0){
            int u, v;
            cin >> u >> v;
            int w = lca(u,v);
            ll Au = depthArr[u] * BIT1.query(tin[u]) + BIT2.query(tin[u]);
            ll Av = depthArr[v] * BIT1.query(tin[v]) + BIT2.query(tin[v]);
            ll Aw = depthArr[w] * BIT1.query(tin[w]) + BIT2.query(tin[w]);
            Cout(Au + Av - 2LL * Aw);;
        } else {
            int v, x;
            cin >> v >> x;
            BIT1.range_update(tin[v], tout[v], x);
            BIT2.range_update(tin[v], tout[v], - (ll)x * depthArr[v]);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 36280
final_rank: 3

code_snippet: // AOJ #2667
// Tree 2025.2.4

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

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(ll n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

const int NMAX = 150001;
vector<int> tree[NMAX];
int parent[NMAX], depth[NMAX], heavy[NMAX], head[NMAX], sz[NMAX], pos[NMAX];
int curPos = 1;
 
int dfs(int u, int p){
    parent[u] = p;
    depth[u] = (p == -1 ? 0 : depth[p] + 1);
    sz[u] = 1;
    heavy[u] = -1;
    int maxSize = 0;
    for(auto v : tree[u]){
        if(v == p) continue;
        int subSize = dfs(v, u);
        if(subSize > maxSize){
            maxSize = subSize;
            heavy[u] = v;
        }
        sz[u] += subSize;
    }
    return sz[u];
}
 
void decompose(int u, int h){
    head[u] = h;
    pos[u] = curPos++;
    if(heavy[u] != -1){
        decompose(heavy[u], h);
    }
    for(auto v : tree[u]){
        if(v == parent[u] || v == heavy[u]) continue;
        decompose(v, v);
    }
}
 
int lcaHLD(int u, int v){
    while(head[u] != head[v]){
        if(depth[head[u]] > depth[head[v]])
            u = parent[head[u]];
        else
            v = parent[head[v]];
    }
    return depth[u] < depth[v] ? u : v;
}
 
struct Fenw {
    int n;
    vector<ll> bit1, bit2;
    Fenw(int n) : n(n) {
        bit1.assign(n+1, 0);
        bit2.assign(n+1, 0);
    }
    void update(vector<ll> &bit, int i, ll delta){
        for(; i <= n; i += i & -i)
            bit[i] += delta;
    }
    void range_update(int l, int r, ll delta){
        if(l > r) return;
        update(bit1, l, delta);
        update(bit1, r+1, -delta);
        update(bit2, l, delta * (l-1));
        update(bit2, r+1, -delta * r);
    }
     ll prefix_sum(int i){
        ll sum1 = 0, sum2 = 0;
        for(int idx = i; idx; idx -= idx & -idx)
            sum1 += bit1[idx];
        for(int idx = i; idx; idx -= idx & -idx)
            sum2 += bit2[idx];
        return sum1 * i - sum2;
    }
    ll range_query(int l, int r){
        if(l > r) return 0;
        return prefix_sum(r) - prefix_sum(l-1);
    }
};
 
Fenw *fenw; // HLD の基底配列上の値を管理する BIT．基底配列の長さは N (頂点数)
 
inline ll segQuery(int l, int r) {
    return fenw->range_query(l, r);
}
 
ll queryPath(int u) {
    ll res = 0;
    while(head[u] != head[0]){
        res += segQuery(pos[head[u]], pos[u]);
        u = parent[head[u]];
    }
    if(u != 0)
        res += segQuery(pos[0] + 1, pos[u]);
    return res;
}
 
int main(){
    int N = Cin(), Q = Cin();

    for (int i = 0; i < N - 1; i++){
        int a = Cin(), b = Cin();
        tree[a].push_back(b);
        tree[b].push_back(a);
    }
 
    dfs(0, -1);
    head[0] = 0;
    decompose(0, 0);
 
    fenw = new Fenw(N);
    for (int i = 0; i < Q; i++){
        int t;
        cin >> t;
        if(t == 0){
            int u, v;
            cin >> u >> v;
            int w = lcaHLD(u, v);
            ll dist = queryPath(u) + queryPath(v) - 2LL * queryPath(w);
            Cout(dist);
        } else {
            int v, x;
            cin >> v >> x;
            int l = pos[v] + 1;
            int r = pos[v] + sz[v] - 1;
            if(l <= r) fenw->range_update(l, r, x);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 29144
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) static_cast<void>(0)
#define debugg(...) static_cast<void>(0)
#define esper(...) static_cast<void>(0)
template<typename T1,typename T2>ostream &operator<<(ostream &os,const pair<T1,T2>&p){os<<p.first<<' '<<p.second;return os;}
#endif
using ll=long long;
using ull=unsigned long long;
using P=pair<ll,ll>;
template<typename T>using minque=priority_queue<T,vector<T>,greater<T>>;
template<typename T>bool chmax(T &a,const T &b){return (a<b?(a=b,true):false);}
template<typename T>bool chmin(T &a,const T &b){return (a>b?(a=b,true):false);}
template<typename T1,typename T2>istream &operator>>(istream &is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T>istream &operator>>(istream &is,vector<T> &a){for(auto &i:a)is>>i;return is;}
template<typename T1,typename T2>void operator++(pair<T1,T2>&a,int n){a.first++,a.second++;}
template<typename T1,typename T2>void operator--(pair<T1,T2>&a,int n){a.first--,a.second--;}
template<typename T>void operator++(vector<T>&a,int n){for(auto &i:a)i++;}
template<typename T>void operator--(vector<T>&a,int n){for(auto &i:a)i--;}
#define reps(i,a,n) for(int i=(a);i<int(n);i++)
#define rep(i,n) reps(i,0,n)
#define all(x) x.begin(),x.end()
#define pcnt(x) __builtin_popcountll(x)
#define fin(x) return cout<<x<<'\n',static_cast<void>(0)
ll myceil(ll a,ll b){return (a+b-1)/b;}
template<typename T,size_t n,size_t id=0>
auto vec(const int (&d)[n],const T &init=T()){
  if constexpr (id<n)return vector(d[id],vec<T,n,id+1>(d,init));
  else return init;
}
void SOLVE();
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout<<fixed<<setprecision(16);
  #ifdef LOCAL
  clock_t start=clock();
  #endif
  int testcase=1;
  //cin>>testcase;
  for(int i=0;i<testcase;i++){
    SOLVE();
  }
  #ifdef LOCAL
  cerr<<"time:";
  cerr<<(clock()-start)/1000;
  cerr<<"ms\n";
  #endif
}
struct HeavyLightDecomposition{
  int n;
  vector<vector<int>>to;
  int root;
  vector<int>par,pathtop,in,out,dep;
  vector<int>sub;
private:
  void st_dfs(int x,int p){
    par[x]=p;
    sub[x]=1;
    for(auto &i:to[x]){
      if(i==p){
        if(i==to[x].back())break;
        else swap(i,to[x].back());
      }
      st_dfs(i,x);
      sub[x]+=sub[i];
      if(sub[i]>sub[to[x][0]]){
        swap(i,to[x][0]);
      }
    }
  }
  void hld_dfs(int x,int p,int &id){
    in[x]=id++;
    for(auto i:to[x])if(i!=p){
      dep[i]=dep[x]+1;
      pathtop[i]=(i==to[x][0]?pathtop[x]:i);
      hld_dfs(i,x,id);
    }
    out[x]=id;
  }
public:
  HeavyLightDecomposition(int n,int root=0):n(n),to(n),sub(n),par(n),in(n),out(n),root(root),pathtop(n),dep(n),g(n){}
  void add_edge(int u,int v){
    to[u].emplace_back(v);
    to[v].emplace_back(u);
  }
  void build(){
    dep[root]=0;
    st_dfs(root,-1);
    pathtop[root]=root;
    int id=0;
    hld_dfs(root,-1,id);
  }
  inline int get(int x)const{return in[x];}
  int lca(int u,int v)const{
    int pu=pathtop[u],pv=pathtop[v];
    while(pathtop[u]!=pathtop[v]){
      if(in[pu]>in[pv])u=par[pu],pu=pathtop[u];
      else v=par[pv],pv=pathtop[v];
    }
    return (in[u]>in[v]?v:u);
  }
  template<typename F>
  void subtree_query(int u ,const F&f){
    static_assert(is_convertible_v<decltype(f),function<void(int,int)>>);
    f(in[u],out[u]);
  }
  template<typename F>
  void path_query(int u,int v,const F&f){
    static_assert(is_convertible_v<decltype(f),function<void(int,int)>>);
    int pu=pathtop[u],pv=pathtop[v];
    while(pathtop[u]!=pathtop[v]){
      if(in[u]>in[v])f(in[pu],in[u]+1),u=par[pu],pu=pathtop[u];
      else f(in[pv],in[v]+1),v=par[pv],pv=pathtop[v];
    }
    if(in[u]>in[v])swap(u,v);
    f(in[u],in[v]+1);
  }
  vector<vector<int>>g;
  int auxiliary_tree(vector<int>v){
    sort(all(v),[&](int x,int y){return in[x]<in[y];});
    v.reserve(v.size()*2-1);
    int vs=v.size();
    reps(i,1,vs)v.push_back(lca(v[i-1],v[i]));
    sort(all(v),[&](int x,int y){return in[x]<in[y];});
    v.erase(unique(all(v)),v.end());
    rep(i,v.size())g[v[i]].clear();
    stack<int>st;
    rep(i,v.size()){
      while(!st.empty()&&out[st.top()]<=in[v[i]])st.pop();
      if(!st.empty()){
        g[st.top()].push_back(v[i]);
        g[v[i]].push_back(st.top());
      }
      st.push(v[i]);
    }
    while(st.size()>1)st.pop();
    return st.top();
  }
};
template <class S,
          auto op,
          auto e,
          class F,
          auto mapping,
          auto composition,
          auto id>
struct lazy_segtree {
    static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                  "op must work as S(S, S)");
    static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                  "e must work as S()");
    static_assert(
        std::is_convertible_v<decltype(mapping), std::function<S(F, S)>>,
        "mapping must work as S(F, S)");
    static_assert(
        std::is_convertible_v<decltype(composition), std::function<F(F, F)>>,
        "composition must work as F(F, F)");
    static_assert(std::is_convertible_v<decltype(id), std::function<F()>>,
                  "id must work as F()");


  public:
    lazy_segtree() : lazy_segtree(0) {}
    explicit lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    explicit lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        size=1;
        log=0;
        while(size<_n){
          size<<=1;
          log++;
        }
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }
  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};
pair<ll,int>op(pair<ll,int>x,pair<ll,int>y){return {x.first+y.first,x.second+y.second};}
pair<ll,int>e(){return {0,0};}
pair<ll,int>mapping(ll f,pair<ll,int>x){return {x.first+f*x.second,x.second};}
ll composition(ll f,ll g){return f+g;}
ll id(){return 0;}
void SOLVE(){
  int n,q;
  cin>>n>>q;
  HeavyLightDecomposition hld(n*2-1);
  rep(i,n-1){
    int a,b;
    cin>>a>>b;
    hld.add_edge(a,i+n);
    hld.add_edge(b,i+n);
  }
  lazy_segtree<pair<ll,int>,op,e,ll,mapping,composition,id>seg(n*2-1);
  hld.build();
  reps(i,n,n*2-1)seg.set(hld.get(i),{0,1});
  while(q--){
    int t;
    cin>>t;
    if(t==0){
      int u,v;
      cin>>u>>v;
      ll ans=0;
      hld.path_query(u,v,[&](int l,int r){ans+=seg.prod(l,r).first;});
      cout<<ans<<endl;
    }
    else{
      int v;
      ll x;
      cin>>v>>x;
      hld.subtree_query(v,[&](int l,int r){seg.apply(l,r,x);});
    }
  }
}
accuracy: 1
time_ms: 460
memory_kb: 77304
final_rank: 15

code_snippet: #if __has_include("all.hpp")

#include "all.hpp"

#else

#include <bits/extc++.h>

// #include <atcoder/all>

#endif

using ll = long long int;

template <class T>
bool chmin(T &x, const T val) {
  if (x > val) {
    x = val;
    return true;
  } else {
    return false;
  }
}

template <class T>
bool chmax(T &x, const T val) {
  if (x < val) {
    x = val;
    return true;
  } else {
    return false;
  }
}

template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
  return is >> p.first >> p.second;
}

template <class... T>
std::istream &operator>>(std::istream &is, std::tuple<T...> &tpl) {
  std::apply([&](auto &&...args) { (is >> ... >> args); }, tpl);
  return is;
}

// template <class mint, atcoder::internal::is_static_modint_t<mint> * =
// nullptr> std::ostream &operator<<(std::ostream &os, const mint &v) {
//   return os << v.val();
// }
//
// template <class mint, atcoder::internal::is_static_modint_t<mint> * =
// nullptr> std::istream &operator>>(std::istream &is, mint &v) {
//   int tmp;
//   is >> tmp;
//   v = tmp;
//   return is;
// }

template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
  for (T &x : v) is >> x;
  return is;
}

template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  for (int i = 0; i < v.size(); i++)
    os << v[i] << (i == v.size() - 1 ? "" : " ");
  return os;
}

struct Initialization {
  Initialization() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
  }
} initialization;

constexpr std::pair<int, int> dir[] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

template <typename T>
using infs = std::numeric_limits<T>;

template <typename T>
class factorials {
 public:
  static size_t n;
  static std::vector<T> fact, inv_fact;

  static void extend(size_t m) {
    if (m <= n) return;
    fact.resize(m + 1);
    inv_fact.resize(m + 1);
    for (size_t i = n + 1; i <= m; i++) fact[i] = fact[i - 1] * i;
    inv_fact[m] = fact[m].inv();
    for (size_t i = m; i > n + 1; i--) inv_fact[i - 1] = inv_fact[i] * i;
    n = m;
  }

  static T inv(int k) {
    extend(k);
    return inv_fact[k];
  }

  static T get(int k) {
    extend(k);
    return fact[k];
  }

  static T perm(int n, int k) {
    if (n < k) return 0;
    if (k < 0) return 0;
    extend(n);
    return fact[n] * inv_fact[n - k];
  }

  static T choose(int n, int k) {
    if (n < k) return 0;
    if (k < 0) return 0;
    extend(n);
    return fact[n] * inv_fact[n - k] * inv_fact[k];
  }
};

template <typename T>
size_t factorials<T>::n = 0;

template <typename T>
std::vector<T> factorials<T>::fact = {1};

template <typename T>
std::vector<T> factorials<T>::inv_fact = {1};

// template <typename T>
// class fps {
//   std::vector<T> v;
//
//  public:
//   using value_type = T;
//   using reference = T &;
//   using const_reference = const T &;
//   using iterator = typename std::vector<T>::iterator;
//   using const_iterator = typename std::vector<T>::const_iterator;
//
//   size_t size() const { return v.size(); }
//
//   const std::vector<T> &data() const { return v; }
//
//   explicit fps(int n) : v(n) {}
//
//   fps(const std::vector<T> &v) : v(v) {}
//   fps(std::vector<T> &&v) : v(v) {}
//
//   template <class InputIterator>
//   fps(InputIterator first, InputIterator last) : v(first, last) {}
//
//   fps(std::initializer_list<T> init) : v(init) {}
//
//   void resize(int n) { v.resize(n); }
//
//   T &operator[](int i) { return v[i]; }
//
//   iterator begin() { return v.begin(); }
//
//   iterator end() { return v.end(); }
//
//   fps take(int n) const {
//     return fps(v.begin(), v.begin() + std::min(n, (int)v.size()));
//   }
//
//   fps diff() const {
//     std::vector<T> res(v.size() - 1);
//     for (int i = 0; i < res.size(); i++) res[i] = v[i + 1] * (i + 1);
//     return fps(res);
//   }
//
//   fps integral() const {
//     std::vector<T> res(v.size() + 1);
//     for (int i = 0; i < v.size(); i++) res[i + 1] = v[i] / (i + 1);
//     return fps(res);
//   }
//
//   fps inv(int deg = -1) const {
//     assert(v[0] != 0);
//
//     if (deg == -1) deg = size();
//     std::vector<T> res(deg);
//
//     res[0] = v[0].inv();
//
//     T inv4 = T(4).inv(), invd = inv4;
//
//     for (int d = 1; d < deg; d <<= 1) {
//       std::vector<T> f(2 * d), g(2 * d);
//
//       std::copy(v.begin(), v.begin() + std::min(2 * d, (int)v.size()),
//                 f.begin());
//       std::copy(res.begin(), res.begin() + d, g.begin());
//
//       atcoder::internal::butterfly(f);
//       atcoder::internal::butterfly(g);
//
//       for (int i = 0; i < 2 * d; i++) f[i] *= g[i];
//
//       atcoder::internal::butterfly_inv(f);
//
//       for (int i = 0; i < d; i++) f[i] = 0;
//
//       atcoder::internal::butterfly(f);
//
//       for (int i = 0; i < 2 * d; i++) f[i] *= g[i];
//
//       atcoder::internal::butterfly_inv(f);
//
//       for (int i = d; i < std::min(2 * d, deg); i++) res[i] = -f[i] * invd;
//
//       invd *= inv4;
//     }
//
//     return res;
//   }
//
//   fps shift(T c) const {
//     std::vector<T> res(size()), ifacts(size());
//
//     T x = 1;
//
//     for (int i = 0; i < size(); i++) {
//       ifacts[i] = x * factorials<T>::inv(i);
//       x *= c;
//     }
//
//     for (int i = 0; i < size(); i++) {
//       res[size() - 1 - i] = v[i] * factorials<T>::get(i);
//     }
//
//     res = atcoder::convolution(res, ifacts);
//
//     res.resize(size());
//
//     std::ranges::reverse(res);
//
//     for (int i = 0; i < size(); i++) {
//       res[i] *= factorials<T>::inv(i);
//     }
//
//     return res;
//   }
//
//   fps operator-() const {
//     fps res(v.size());
//     for (int i = 0; i < v.size(); i++) res[i] = -v[i];
//     return res;
//   }
//
//   fps &operator+=(const fps &rhs) {
//     if (v.size() < rhs.v.size()) v.resize(rhs.v.size());
//     for (int i = 0; i < rhs.v.size(); i++) v[i] += rhs.v[i];
//     return *this;
//   }
//
//   fps &operator-=(const fps &rhs) {
//     if (v.size() < rhs.v.size()) v.resize(rhs.v.size());
//     for (int i = 0; i < rhs.v.size(); i++) v[i] -= rhs.v[i];
//     return *this;
//   }
//
//   fps &operator*=(const fps &rhs) {
//     return *this = atcoder::convolution(v, rhs.v);
//   }
//
//   fps &operator/=(const fps &rhs) { return *this *= rhs.inv(); }
//
//   fps &operator+=(const T &rhs) {
//     if (v.size() == 0) v.resize(1);
//     v[0] += rhs;
//     return *this;
//   }
//
//   fps &operator-=(const T &rhs) {
//     if (v.size() == 0) v.resize(1);
//     v[0] -= rhs;
//     return *this;
//   }
//
//   fps &operator*=(const T &rhs) {
//     for (int i = 0; i < v.size(); i++) v[i] *= rhs;
//     return *this;
//   }
//
//   fps &operator/=(const T &rhs) {
//     T rhs_inv = rhs.inv();
//     for (int i = 0; i < v.size(); i++) v[i] *= rhs_inv;
//     return *this;
//   }
//
//   friend fps operator+(const fps &lhs, const fps &rhs) {
//     return fps(lhs) += rhs;
//   }
//
//   friend fps operator-(const fps &lhs, const fps &rhs) {
//     return fps(lhs) -= rhs;
//   }
//
//   friend fps operator*(const fps &lhs, const fps &rhs) {
//     return fps(lhs) *= rhs;
//   }
//
//   friend fps operator/(const fps &lhs, const fps &rhs) {
//     return fps(lhs) /= rhs;
//   }
//
//   friend fps operator+(const fps &lhs, const T &rhs) { return fps(lhs) +=
//   rhs; }
//
//   friend fps operator-(const fps &lhs, const T &rhs) { return fps(lhs) -=
//   rhs; }
//
//   friend fps operator*(const fps &lhs, const T &rhs) { return fps(lhs) *=
//   rhs; }
//
//   friend fps operator/(const fps &lhs, const T &rhs) { return fps(lhs) /=
//   rhs; }
//
//   friend fps operator+(const T &lhs, const fps &rhs) { return fps(rhs) +=
//   lhs; }
//
//   friend fps operator-(const T &lhs, const fps &rhs) {
//     return -(fps(rhs) -= lhs);
//   }
//
//   friend fps operator*(const T &lhs, const fps &rhs) { return fps(rhs) *=
//   lhs; }
// };
//
// template <typename T>
// T bostan_mori(int n, fps<T> P, fps<T> Q) {
//   assert(P.size() < Q.size());
//
//   P.resize(Q.size() - 1);
//
//   while (n) {
//     fps qm = Q;
//     for (int i = 1; i < Q.size(); i += 2) qm[i] = -qm[i];
//
//     fps U = P * qm;
//     fps V = Q * qm;
//
//     for (int i = n & 1; i < U.size(); i += 2) P[i / 2] = U[i];
//     for (int i = 0; i < V.size(); i += 2) Q[i / 2] = V[i];
//
//     n /= 2;
//   }
//
//   return P[0] / Q[0];
// }

// using mint = atcoder::modint998244353;
// using mint = atcoder::modint1000000007;

// using fs = factorials<mint>;

struct S {
  int num;
  ll val;
};

using F = ll;

S op(S a, S b) {
  return {a.num + b.num, a.val + b.val};
}

S e() {
  return {1, 0};
}

S mapping(F f, S x) {
  return {x.num, x.val + f * x.num};
}

F composition(F f, F g) {
  return f + g;
}

F id() {
  return 0;
}


#include <algorithm>
#include <cassert>
#include <functional>
#include <vector>


#ifdef _MSC_VER
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace atcoder {

namespace internal {

#if __cplusplus >= 202002L

using std::bit_ceil;

#else

unsigned int bit_ceil(unsigned int n) {
    unsigned int x = 1;
    while (x < (unsigned int)(n)) x *= 2;
    return x;
}

#endif

int countr_zero(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

constexpr int countr_zero_constexpr(unsigned int n) {
    int x = 0;
    while (!(n & (1 << x))) x++;
    return x;
}

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

#if __cplusplus >= 201703L

template <class S,
          auto op,
          auto e,
          class F,
          auto mapping,
          auto composition,
          auto id>
struct lazy_segtree {
    static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                  "op must work as S(S, S)");
    static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                  "e must work as S()");
    static_assert(
        std::is_convertible_v<decltype(mapping), std::function<S(F, S)>>,
        "mapping must work as F(F, S)");
    static_assert(
        std::is_convertible_v<decltype(composition), std::function<F(F, F)>>,
        "compostiion must work as F(F, F)");
    static_assert(std::is_convertible_v<decltype(id), std::function<F()>>,
                  "id must work as F()");

#else

template <class S,
          S (*op)(S, S),
          S (*e)(),
          class F,
          S (*mapping)(F, S),
          F (*composition)(F, F),
          F (*id)()>
struct lazy_segtree {

#endif

  public:
    lazy_segtree() : lazy_segtree(0) {}
    explicit lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    explicit lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        size = (int)internal::bit_ceil((unsigned int)(_n));
        log = internal::countr_zero((unsigned int)size);
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e()));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

}  // namespace atcoder


using segtree = atcoder::lazy_segtree<S, op, e, F, mapping, composition, id>;

int main() {
  int N, Q;
  std::cin >> N >> Q;
  std::vector<std::vector<int>> graph(N);

  for (int i = 0; i < N - 1; i++) {
    int a, b;
    std::cin >> a >> b;
    graph[a].push_back(b);
  }

  std::vector<int> depth(N, -1), parent(N, -1), size(N, 1), in(N), out(N),
      head(N);

  depth[0] = 0;

  auto rec_size = [&](auto self, int v) -> int {
    for (int &w : graph[v]) {
      if (depth[w] != -1) continue;
      depth[w] = depth[v] + 1;
      parent[w] = v;
      size[v] += self(self, w);
      if (size[w] > size[graph[v][0]]) std::swap(w, graph[v][0]);
    }

    return size[v];
  };

  rec_size(rec_size, 0);

  int idx = 0;
  auto rec_hld = [&](auto self, int v, int h) -> void {
    in[v] = idx++;
    head[v] = h;

    for (int w : graph[v]) {
      if (w == parent[v]) continue;
      if (w == graph[v][0]) {
        self(self, w, h);
      } else {
        self(self, w, w);
      }
    }

    out[v] = idx;
  };

  rec_hld(rec_hld, 0, 0);

  segtree segt(N);

  for (int i = 0; i < Q; i++) {
    int t;
    std::cin >> t;

    if (t == 0) {
      int u, v;
      std::cin >> u >> v;

      ll tmp = 0;

      while (head[u] != head[v]) {
        if (depth[head[u]] < depth[head[v]]) std::swap(u, v);
        tmp += segt.prod(in[head[u]], in[u] + 1).val;
        u = parent[head[u]];
      }

      if (depth[u] < depth[v]) std::swap(u, v);
      tmp += segt.prod(in[v] + 1, in[u] + 1).val;

      std::cout << tmp << '\n';
    } else {
      int v;
      ll x;
      std::cin >> v >> x;

      segt.apply(in[v] + 1, out[v], x);
    }
  }
}
accuracy: 1
time_ms: 230
memory_kb: 46140
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (ll i = s; i < (ll)(t); i++)
#define rrep(i, s, t) for(ll i = (ll)(t) - 1; i >= (ll)(s); i--)
#define all(x) begin(x), end(x)
#define TT template<typename T>
TT using vec = vector<T>;
TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

struct io_setup {
    io_setup() {
        ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} io_setup;


TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

TT int LB(vector<T>& v, T x) { return lower_bound(all(v), x) - begin(v);}
TT int UB(vector<T>& v, T x) { return upper_bound(all(v), x) - begin(v);}

const int inf = 1001001001;
const ll INF = 2002002002002002002;



template<class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazysegtree {
    int n;
    int sz;
    int log;
    vector<S> d;
    vector<F> lz;
	lazysegtree(){}
    lazysegtree(int n) : lazysegtree(vector<S>(n, e())) {}
    lazysegtree(const vector<S> &v) : n((int)(v.size())) {
        log = 1;
        while((1 << log) < n) log++;
        sz = 1 << log;
        d.resize(2*sz, e());
        lz.resize(2*sz, id());
        rep(i, 0, n) d[sz+i] = v[i];
        rrep(i, 1, sz) update(i);
    }

    void update(int i) {
        d[i] = op(d[i<<1], d[i<<1|1]);
    }

    void all_apply(int i, F f) {
        d[i] = mapping(f, d[i]);
        if(i < sz) lz[i] = composition(f, lz[i]);
    }

    void push(int k) {
        all_apply(k<<1, lz[k]);
        all_apply(k<<1|1, lz[k]);
        lz[k] = id();
    }


    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += sz;
        rrep(i, 1, log+1) push(p >> i);
        d[p] = x;
        rep(i, 1, log+1) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < n);
        p += sz;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return e();

        l += sz;
        r += sz;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < n);
        p += sz;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;

        l += sz;
        r += sz;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= n);
        assert(g(e()));
        if (l == n) return n;
        l += sz;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < sz) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - sz;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return n;
    }

   
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= n);
        assert(g(e()));
        if (r == 0) return 0;
        r += sz;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < sz) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - sz;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

};
/*
@brief lazysegtree
@docs doc/lazysegtree.md
*/



struct HLD {
    using vi = vec<int>;
    using pi = pair<int, int>;
    vi in;
    vi out;
    vi par;//親
    vi root;//成分のtop
    int n;
    int r;//根
    
  
    HLD(vec<vi>& g, int a): n(g.size()), r(a) {
        vi siz(n, 0);
        in = vi(n), out = vi(n), root = vi(n), par = vi(n, -1);

        auto dfs_siz = [&](auto f, int v) -> void {
            siz[v]++;
            for(int& to : g[v]) if(to != par[v]) {
                par[to] = v;
                f(f, to);
                siz[v] += siz[to];
                if(siz[to] > siz[g[v][0]] || g[v][0] == par[v]) swap(to, g[v][0]);
            }
            return;
        };

        dfs_siz(dfs_siz, r); 
		int t = 0;
    
        auto dfs_hld = [&](auto f, int v) -> void {
            in[v]=t++;
            for(int to : g[v]) if(to != par[v]) {
                root[to] = (to == g[v][0] ? root[v] : to);
                f(f, to);
            }
            out[v] = t;
        };

        dfs_hld(dfs_hld, r);
    }

    int lca(int a, int b) {
        while(1) {
            if(in[a] > in[b]) swap(a, b);
            if(root[a] == root[b]) return a;
            b = par[root[b]];
        }
    }

    //lcaのみが必要ならここまで

    vec<pi> path(int s, int t, bool edge) {
        vec<pi> ls, rs;
        while(root[s] != root[t]) {
            if(in[s] > in[t]) {
                ls.emplace_back(in[s] + 1, in[root[s]]);//上り
                s = par[root[s]];
            }
            else {
                rs.emplace_back(in[root[t]], in[t] + 1);//下り
                t = par[root[t]];
            }
        }

        if(in[s] > in[t]) ls.emplace_back(in[s] + 1, in[t] + edge);//上り
        else rs.emplace_back(in[s] + edge, in[t] + 1);//下り
        
        reverse(all(rs));
        for(auto &p : rs) ls.push_back(p);
        return ls;
    }

    pi subtree(int u, bool edge) {
        return pi(in[u]+edge, out[u]);
    }
};  


struct S {
	ll v;
	int siz;
};
S op(S l, S r) {
	return S{l.v+r.v, l.siz + r.siz};
}
S e() {
	return S{0, 0};
}
using F = ll;

S mapping(F f, S s) {
	return S{f*s.siz + s.v, s.siz};
}

F composition(F l, F r) {
	return l + r;
}

F id() {
	return 0LL;
}


int main() {
	int N, Q;
	cin >> N >> Q;
	vec<ll> A(N), B(N);
	vec<vec<int>> G(N);
	rep(i,1,N) {
		ll a, b;
		cin >> a >> b;
		G[a].push_back(b);
		G[b].push_back(a);
	}

	HLD hld(G, 0);
	vec<S> C(N, {0, 1});
	lazysegtree<S, op, e, F, mapping, composition, id> seg(C);

	
	while(Q--) {
		ll t;
		cin >> t;
		if(t==0) {
			ll u, v;
			cin >> u >> v;
			ll res = 0;
			auto ps = hld.path(u, v, true);
			for(auto [l, r] : ps) {
				if(l >= r) swap(l, r);
				res += seg.prod(l, r).v;
			}
			cout << res << '\n';
		}
		else {
			ll v, x;
			cin >> v >> x;
			auto [l, r] = hld.subtree(v, true);
			seg.apply(l, r, x);
		}
	}
	
	
}
accuracy: 1
time_ms: 240
memory_kb: 44684
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (ll i = s; i < (ll)(t); i++)
#define rrep(i, s, t) for(ll i = (ll)(t) - 1; i >= (ll)(s); i--)
#define all(x) begin(x), end(x)
#define TT template<typename T>
TT using vec = vector<T>;
TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

struct io_setup {
    io_setup() {
        ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} io_setup;

TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

const int inf = 1001001001;
const ll INF = 2002002002002002002;

// atcoder::lazysegtree syakyo

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

}  // namespace atcoder

namespace atcoder {

template <class S,
          S (*op)(S, S),
          S (*e)(),
          class F,
          S (*mapping)(F, S),
          F (*composition)(F, F),
          F (*id)()>
struct lazy_segtree {
  public:
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e()));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

}  // namespace atcoder


struct S{
	int d;
	ll sm;
};
S op(S a,S b){
	a.d+=b.d;
	a.sm+=b.sm;
	return a;
}
S e(){
	return {0,0};
}
using F=ll;
S mapping(F f,S x){
	x.sm+=f*x.d;
	return x;
}
F comp(F f,F g){
	return f+g;
}
F id(){
	return 0;
}
using segtree1=atcoder::lazy_segtree<S,op,e,F,mapping,comp,id>;

S op2(S a,S b){
	if(a.d<b.d) return a;
	return b;
}
S e2(){
	return {(int)1e9,0};
}
using segtree2=atcoder::lazy_segtree<S,op2,e2,F,mapping,comp,id>;


int main(){
	int n,q;
	cin>>n>>q;
	vector<vector<int>> g(n);
	vector<int> root(n,-1);
	rep(i,0,n-1){
		int a,b;
		cin>>a>>b;
		g.at(a).push_back(b);
		root.at(b)=a;
	}
	vector<S> tmp1;
	vector<S> tmp2;
	vector<int> in(n),ou(n);
	auto dfs=[&](auto self,int nw,int pr=-1) ->void {
		in.at(nw)=tmp1.size();
		tmp1.push_back({1,0});
		tmp2.push_back({nw,0});
		for(int nx:g.at(nw)){
			if(nx==pr) continue;
			self(self,nx,nw);
		}
		ou.at(nw)=tmp1.size();
		tmp1.push_back({-1,0});
		tmp2.push_back({nw,0});
	};
	dfs(dfs,0);
	segtree1 dist(tmp1);
	segtree2 lca(tmp2);
	auto get_lca=[&](int a,int b){
		auto[l,r]=minmax({in.at(a),in.at(b)});
		l++;
		if(l==r) return min(a,b);
		return root.at(lca.prod(l,r).d);
	};
	auto get_dist=[&](int x){
		return dist.prod(0,in.at(x)+1).sm;
	};
	rep(Qi,0,q){
		int t;
		cin>>t;
		if(t==0){
			int u,v;
			cin>>u>>v;
			if(u==v){
				cout<<"0\n";
				continue;
			}
			int x=get_lca(u,v);
			cout<<get_dist(u)+get_dist(v)-get_dist(x)*2<<"\n";			
		}else{
			int v,x;
			cin>>v>>x;
			int l=in.at(v);
			int r=ou.at(v);
			l++;
			dist.apply(l,r,x);
		}
	}
}
accuracy: 1
time_ms: 170
memory_kb: 84092
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (ll i = s; i < (ll)(t); i++)
#define rrep(i, s, t) for(ll i = (ll)(t) - 1; i >= (ll)(s); i--)
#define all(x) begin(x), end(x)
#define TT template<typename T>
TT using vec = vector<T>;
TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

struct io_setup {
    io_setup() {
        ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} io_setup;

TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

const int inf = 1001001001;
const ll INF = 2002002002002002002;

// atcoder::lazysegtree syakyo

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

}  // namespace atcoder

namespace atcoder {

template <class S,
          S (*op)(S, S),
          S (*e)(),
          class F,
          S (*mapping)(F, S),
          F (*composition)(F, F),
          F (*id)()>
struct lazy_segtree {
  public:
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e()));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

}  // namespace atcoder


struct S{
	int d;
	ll sm;
};
S op(S a,S b){
	a.d+=b.d;
	a.sm+=b.sm;
	return a;
}
S e(){
	return {0,0};
}
using F=ll;
S mapping(F f,S x){
	x.sm+=f*x.d;
	return x;
}
F comp(F f,F g){
	return f+g;
}
F id(){
	return 0;
}
using segtree1=atcoder::lazy_segtree<S,op,e,F,mapping,comp,id>;

using S2=ll;
S2 op2(S2 a,S2 b){
	return min(a,b);
}
S2 e2(){
	return 1e18;
}
S2 mapping2(F f,S2 x){
	return f+x;
}
using segtree2=atcoder::lazy_segtree<S2,op2,e2,F,mapping2,comp,id>;


int main(){
	int n,q;
	cin>>n>>q;
	vector<vector<int>> g(n);
	vector<int> root(n,-1);
	rep(i,0,n-1){
		int a,b;
		cin>>a>>b;
		g.at(a).push_back(b);
		root.at(b)=a;
	}
	vector<S> tmp1;
	vector<S2> tmp2;
	vector<int> in(n),ou(n,-1);
	auto dfs=[&](auto self,int nw,int pr=-1) ->void {
		in.at(nw)=tmp1.size();
		tmp1.push_back({1,0});
		tmp2.push_back(nw);
		for(int nx:g.at(nw)){
			if(nx==pr) continue;
			self(self,nx,nw);
		}
		ou.at(nw)=tmp1.size();
		tmp1.push_back({-1,0});
		tmp2.push_back(nw);
	};
	dfs(dfs,0);
	segtree1 dist(tmp1);
	segtree2 lca(tmp2);
	auto get_lca=[&](int a,int b){
		auto[l,r]=minmax({in.at(a),in.at(b)});
		l++;
		if(l==r) return min(a,b);
		return root.at(lca.prod(l,r));
	};
	auto get_dist=[&](int x){
		return dist.prod(0,in.at(x)+1).sm;
	};
	rep(Qi,0,q){
		int t;
		cin>>t;
		if(t==0){
			int u,v;
			cin>>u>>v;
			if(u==v){
				cout<<"0\n";
				continue;
			}
			int x=get_lca(u,v);
			cout<<get_dist(u)+get_dist(v)-get_dist(x)*2<<"\n";			
		}else{
			int v,x;
			cin>>v>>x;
			int l=in.at(v);
			int r=ou.at(v);
			l++;
			dist.apply(l,r,x);
		}
	}
}
accuracy: 1
time_ms: 160
memory_kb: 77800
final_rank: 10

code_snippet: #include <bits/stdc++.h>
#define rep(i,s,n) for (int i = (int)(s); i < (int)(n); i++)
#define all(v) (v).begin(),(v).end()
using namespace std;
using ll = long long;

template<typename T>
bool chmin(T &a, const T &b){
    if (a <= b) return false;
    a = b;
    return true;
}


template<typename T>
bool chmax(T &a, const T &b){
    if (a >= b) return false;
    a = b;
    return true;
}

template<class S, S(*op)(S,S), S(*e)(), class F, S (*mapping)(F,S), F(*composition)(F,F), F(*id)()>
struct lazysegtree {
    private:
        int n, lg2, sz;
        vector<S> d;
        vector<F> lz;
        void update(int i){
            d[i] = op(d[2*i],d[2*i+1]);
        }
        void all_apply(int i, F f){
            d[i] = mapping(f,d[i]);
            if(i<sz)lz[i]=composition(f,lz[i]);
        }
        void push(int i){
            all_apply(2*i, lz[i]);
            all_apply(2*i+1,lz[i]);
            lz[i] = id();
        }
    public:
        lazysegtree(int _n):lazysegtree(vector<S>(_n,e())){}
        lazysegtree(const vector<S>&v):n(v.size()){
            lg2=0;
            while((1<<lg2)<n)lg2++;
            sz=1<<lg2;
            d=vector<S>(2*sz,e());
            lz=vector<F>(2*sz,id());
            for(int i=0;i<n;i++) d[sz+i]=v[i];
            for(int i=sz-1;i>=1;i--)update(i);
        }
        S prod(int l, int r){
            if(l==r)return e();
            l+=sz;
            r+=sz;
            for(int i=lg2; i>=1; i--){
                if(((l>>i)<<i)!=l) push(l>>i);
                if(((r>>i)<<i)!=r)push((r-1)>>i);
            }
            S sml=e(), smr=e();
            while(l<r){
                if(l&1)sml=op(sml,d[l++]);
                if(r&1)smr=op(d[--r],smr);
                l>>=1;r>>=1;
            }
            return op(sml,smr);
        }
        void apply(int l, int r, F f){
            if (l==r) return;
            l+=sz;
            r+=sz;
            for (int i=lg2;i>=1;i--){
                if(((l>>i)<<i)!=l)push(l>>i);
                if(((r>>i)<<i)!=r)push((r-1)>>i);
            }
            {
                int l2 = l, r2 = r;
                while(l<r){
                    if(l&1)all_apply(l++,f);
                    if(r&1)all_apply(--r,f);
                    l>>=1;r>>=1;
                }
                l=l2;
                r=r2;
            }
            rep(i,1,lg2+1){
                if(((l>>i)<<i)!=l) update(l>>i);
                if(((r>>i)<<i)!=r)update((r-1)>>i);
            }
        }
};

struct HLD {
    void dfs_sz(int v){
        for(auto&nv:g[v]){
            if(nv==par[v])continue;
            par[nv]=v;
            depth[nv]=depth[v]+1;
            dfs_sz(nv);
            sz[v]+=sz[nv];
            if(sz[nv]>sz[g[v][0]] || g[v][0]==par[v]) swap(nv,g[v][0]);
        }
    }
    void dfs_hld(int v){
        in[v]=t++;
        for(auto nv:g[v]){
            if(nv == par[v]) continue;
            nxt[nv] = (nv == g[v][0] ? nxt[v]:nv);
            dfs_hld(nv);
        }
        out[v] = t;
    }

    vector<pair<int,int>> ascend(int u, int v) const {
        vector<pair<int,int>> res;
        while(nxt[u]!=nxt[v]){
            res.emplace_back(in[u], in[nxt[u]]);
            u=par[nxt[u]];
        }
        if(u!=v)res.emplace_back(in[u],in[v]+1);
        return res;
    }

    vector<pair<int,int>> descend(int u, int v) const {
        if (u==v) return {};
        if(nxt[u]==nxt[v]) return{{in[u]+1, in[v]}};
        auto res = descend(u,par[nxt[v]]);
        res.emplace_back(in[nxt[v]],in[v]);
        return res;
    }

    HLD(const vector<vector<int>> &gh, int root = 0):
        n(gh.size()),g(gh),sz(n,1),in(n),out(n),nxt(n),par(n,-1),depth(n,0){
            nxt[root] = root;
            dfs_sz(root);
            dfs_hld(root);
        }
    
    int idx(int u) const {
        return in[u];
    }

    int lca(int u, int v) const {
        while(nxt[u] != nxt[v]){
            if(in[u]<in[v]) swap(u, v);
            u=par[nxt[u]];
        }
        return depth[u] < depth[v] ? u : v;
    }

    template<class F>
    void path_noncommutative_query(int u, int v, bool vertex, const F &f) const {
        int l = lca(u, v);
        for (auto [a, b]: ascend(u, l)) f(a+1, b);
        if (vertex) f(in[l], in[l]+1);
        for (auto [a, b]: descend(l, v)) f(a, b+1);
    }

    template <class F> void subtree_query(int u, bool vertex, const F &f){
        f(in[u] + int(!vertex), out[u]);
    }

        int n, t = 0;
        vector<vector<int>> g;
        vector<int> sz,in,out,nxt,par,depth;
};

using pll = pair<ll,ll>;
pll op(pll a, pll b){
    return pll(a.first+b.first,a.second+b.second);
}
pll e(){
    return pll(0,0);
}
pll mapping(ll f, pll x){
    x.first += f * x.second;
    return x;
}

ll composition(ll f, ll g){
    return f + g;
}

ll ident(){
    return 0;
}

void solve(){
    int n, q; cin >> n >> q;
    vector<vector<int>> g(n);
    rep(i,0,n-1){
        int u, v; cin >> u >> v;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    HLD tr(g);
    lazysegtree<pll,op,e,ll,mapping,composition,ident> seg([&]{
        vector<pll> a(n,{0,1});
        return a;
    }());
    ll dist = 0;
    auto prod = [&](int l, int r){
        if (l > r) swap(l,r);
        // cout << "prod" << l << ' ' << r << endl;
        dist += seg.prod(l,r).first;
        // cout << dist << endl;
    };
    ll apr = 0;
    auto apply = [&](int l, int r){
        seg.apply(l,r,apr);
    };
    while (q--){
        int t; cin >> t;
        if (t == 0){
            int u, v; cin >> u >> v;
            dist = 0;
            tr.path_noncommutative_query(u,v,false,prod);
            cout << dist << '\n';
        }
        else {
            int v; cin >> v;
            ll x; cin >> x;
            apr = x;
            tr.subtree_query(v,false,apply);
        }
    }
}

int main(){
    cin.tie(0)->sync_with_stdio(0);
    solve();
}
accuracy: 1
time_ms: 250
memory_kb: 46928
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (ll i = s; i < (ll)(t); i++)
#define rrep(i, s, t) for(ll i = (ll)(t) - 1; i >= (ll)(s); i--)
#define all(x) begin(x), end(x)
#define TT template<typename T>
TT using vec = vector<T>;
TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

struct io_setup {
    io_setup() {
        ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} io_setup;


TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

TT int LB(vector<T>& v, T x) { return lower_bound(all(v), x) - begin(v);}
TT int UB(vector<T>& v, T x) { return upper_bound(all(v), x) - begin(v);}

const int inf = 1001001001;
const ll INF = 2002002002002002002;



template<class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazysegtree {
    int n;
    int sz;
    int log;
    vector<S> d;
    vector<F> lz;
	lazysegtree(){}
    lazysegtree(int n) : lazysegtree(vector<S>(n, e())) {}
    lazysegtree(const vector<S> &v) : n((int)(v.size())) {
        log = 1;
        while((1 << log) < n) log++;
        sz = 1 << log;
        d.resize(2*sz, e());
        lz.resize(2*sz, id());
        rep(i, 0, n) d[sz+i] = v[i];
        rrep(i, 1, sz) update(i);
    }

    void update(int i) {
        d[i] = op(d[i<<1], d[i<<1|1]);
    }

    void all_apply(int i, F f) {
        d[i] = mapping(f, d[i]);
        if(i < sz) lz[i] = composition(f, lz[i]);
    }

    void push(int k) {
        all_apply(k<<1, lz[k]);
        all_apply(k<<1|1, lz[k]);
        lz[k] = id();
    }


    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += sz;
        rrep(i, 1, log+1) push(p >> i);
        d[p] = x;
        rep(i, 1, log+1) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < n);
        p += sz;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return e();

        l += sz;
        r += sz;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < n);
        p += sz;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;

        l += sz;
        r += sz;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= n);
        assert(g(e()));
        if (l == n) return n;
        l += sz;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < sz) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - sz;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return n;
    }

   
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= n);
        assert(g(e()));
        if (r == 0) return 0;
        r += sz;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < sz) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - sz;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

};
/*
@brief lazysegtree
@docs doc/lazysegtree.md
*/

template<class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct HLD {
	using vi = vec<int>;
	using vvi = vec<vi>;
	vi siz;
	vi in;
	vi rev;
	vi out;
	vi par;
	vi head;
	lazysegtree<S, op, e, F, mapping, composition, id> seg;
	int N;
	int size = 1;
	int root;

	HLD(vvi &G, int _root) : root(_root) {
		N = int(G.size()) - 1;
		par.resize(N+1);
		iota(all(par), 0);
		siz.resize(N+1, 1);
		in.assign(N+1, -1);
		rev.resize(N+1, -1);
		out.resize(N+1, -1);
		head.resize(N+1);
		vec<S> fi(N+1, S{0, 1});
		fi[0] = S{0, 0};
		seg = lazysegtree<S, op, e, F, mapping, composition, id> (fi);

		auto dfs_siz = [&](auto f, int now, int prev) -> void {
			int sum = 1;
			for(int to : G[now]) {
				if(to == prev) continue;
				f(f, to, now);
				sum += siz[to];
			}
			siz[now] = sum;
			return;
		};

		dfs_siz(dfs_siz, root, -1);
		rep(i, 0, N+1) {
			sort(all(G[i]), [&](int a, int b) {
				return siz[a] > siz[b];
			});
		}

		int idx = 1;
		auto dfs_bunkai = [&](auto f, int now, int prev, int hed) -> void {
			in[now] = idx;
			rev[idx] = now;
			idx++;
		    par[now] = prev;
			if(hed == -1) hed = now;
			head[now] = hed;
			bool flag = true;
			rep(i, 0, int(G[now].size())) {
				if(in[G[now][i]] != -1) continue;
				if(flag) f(f, G[now][i], now, hed), flag = false;
				else f(f, G[now][i], now, -1);
			}
			out[now] = idx;
			return;
		};

		dfs_bunkai(dfs_bunkai, root, root, -1);
	}

		
	    S get__(int u, int v) {
			int w = getLCA(u, v);
			S L = e(), R = e();

			while(u != w) {
				int hed = max<int>(in[head[u]], in[w]+1);
				L = op(seg.prod(hed, in[u] + 1), L);
				u = par[rev[hed]];
			}
			L = op(seg.prod(in[w], in[w]+1), L);


			while(v != w) {
				int hed = max<int>(in[head[v]], in[w]+1);

				R = op(seg.prod(hed, in[v] + 1), R);
				v = par[rev[hed]];
			}
			return op(L, R);
		}

		void change_sub(int u, F f) {
			int l = in[u];
			int r = out[u];
			seg.apply(l, r, f);
			seg.apply(l, l+1, -f);
		}

		ll get(int u, int v) {
			return get__(u, v).v - get__(u, u).v;
		}

		int getLCA(int a, int b) {
			while(true) {
				if(in[a] > in[b]) swap(a, b);
				if(head[a] == head[b]) return a;
				b = par[head[b]];
			}
		}

		
	
};

struct S {
	ll v;
	int siz;
};
S op(S l, S r) {
	return S{l.v+r.v, l.siz + r.siz};
}
S e() {
	return S{0, 0};
}
using F = ll;

S mapping(F f, S s) {
	return S{f*s.siz + s.v, s.siz};
}

F composition(F l, F r) {
	return l + r;
}

F id() {
	return 0LL;
}
int main() {
	int N, Q;
	cin >> N >> Q;
	vec<ll> A(N+1), B(N+1);
	vec<vec<int>> G(N+1);
	rep(i,1,N) {
		ll a, b;
		cin >> a >> b;
		a++, b++;
		G[a].push_back(b);
		G[b].push_back(a);
	}

	HLD<S, op, e, F, mapping, composition, id> hld(G, 1);

	
	while(Q--) {
		ll t;
		cin >> t;
		if(t==0) {
			ll u, v;
			cin >> u >> v;
			u++, v++;
			ll lca = hld.getLCA(u, v);
			ll a = hld.get(1, u);
			ll b = hld.get(1, v);
			ll c = hld.get(1, lca);

			cout << a + b - 2 * c << endl;
		}
		else {
			ll v, x;
			cin >> v >> x;
			v++;
			hld.change_sub(v, x);
		}
	}
	
	
}
accuracy: 1
time_ms: 520
memory_kb: 48092
final_rank: 13

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

class HeavyLightDecomposition {
   private:
   vector<vector<int>> g;
   vector<int> sz, in, out, head, rev, par;
   bool built;

   void dfs_sz(int v, int p) {
      par[v] = p;
      sz[v] = 1;
      if(!g[v].empty() && g[v][0] == p) swap(g[v][0], g[v].back());
      for(auto&& u : g[v])
         if(u != p) {
            dfs_sz(u, v);
            sz[v] += sz[u];
            if(sz[u] > sz[g[v][0]]) swap(u, g[v][0]);
         }
   }

   void dfs_hld(int v, int p, int& t) {
      in[v] = t++;
      rev[in[v]] = v;
      for(auto&& u : g[v])
         if(u != p) {
            head[u] = (u == g[v][0] ? head[v] : u);
            dfs_hld(u, v, t);
         }
      out[v] = t;
   }

   public:
   explicit HeavyLightDecomposition(int n) : g(n), sz(n), in(n), out(n), head(n), rev(n), par(n), built(false) {}
   explicit HeavyLightDecomposition(const vector<vector<int>>& g, int root = 0)
       : g(g), sz(g.size()), in(g.size()), out(g.size()), head(g.size()), rev(g.size()), par(g.size()) {
      build(root);
   }

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

   void build(int r = 0) {
      dfs_sz(r, -1);
      int t = 0;
      head[r] = r;
      dfs_hld(r, -1, t);
      built = true;
   }

   int lca(int u, int v) {
      assert(built);
      while(true) {
         if(in[u] > in[v]) swap(u, v);
         if(head[u] == head[v]) return u;
         v = par[head[v]];
      }
   }

   pair<int, int> subtree_query(int u) {
      assert(built);
      return pair<int, int>{in[u], out[u]};
   }

   vector<pair<int, int>> node_query(int u, int v) {
      assert(built);
      vector<pair<int, int>> res;
      while(true) {
         if(in[u] > in[v]) swap(u, v);
         if(head[u] == head[v]) break;
         res.emplace_back(in[head[v]], in[v] + 1);
         v = par[head[v]];
      }
      res.emplace_back(in[u], in[v] + 1);
      return res;
   }

   vector<pair<int, int>> edge_query(int u, int v) {
      assert(built);
      vector<pair<int, int>> res;
      while(true) {
         if(in[u] > in[v]) swap(u, v);
         if(head[u] == head[v]) break;
         res.emplace_back(in[head[v]], in[v] + 1);
         v = par[head[v]];
      }
      res.emplace_back(in[u] + 1, in[v] + 1);
      return res;
   }

   int operator[](int u) {
      assert(built);
      return in[u];
   }
};

using ll = long long;
#define rep(i,a,b) for(ll i = a; i < b; i++)
#define all(a) (a).begin(), (a).end()
using S = array<ll, 3>;
S op(S a, S b){
    return {a[0] + b[0], a[1]+b[1], a[2]+b[2] + a[1]*b[0]};
}
S e(){
    return {0, 0, 0};
}

struct segtree{
    int n;
    vector<S> node;

    segtree(int n_){
        n = 1;
        while(n < n_) n *= 2;
        node.resize(2*n-1, e());
    }

    void set(int i, S x){
        i += n-1;
        node[i] = x;
        while(i > 0){
            i = (i-1)/2;
            node[i] = op(node[i*2+1],node[i*2+2]);
        }
    }

    S _get(int a, int b, int k, int l, int r){
        if(r < 0) r = n;
        if(r <= a || b <= l) return e();
        if(a <= l && r <= b) return node[k];
        S vl = _get(a,b,k*2+1,l,(l+r)/2);
        S vr = _get(a,b,k*2+2,(l+r)/2,r);
        return op(vl, vr);
    }

    S get(int a, int b){
        return _get(a,b,0,0,n);
    }
};


int main(){
    int n,q;
    cin >> n >> q;
    vector<vector<int>> g(n);
    rep(i,0,n-1){
        int a,b;
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    HeavyLightDecomposition hld(g);

    vector<ll> nw(n,0);
    segtree tr(n);

    auto query = [&](vector<pair<int,int>> v) -> ll {
        S res = e();
        reverse(all(v));
        v.back().second--;
        for(auto&& [l,r] : v){
            res = op(res, tr.get(l,r));
        }
        return res[2];
    };
    rep(i,0,n){
        tr.set(i,{1,0,0});
    }

    rep(i,0,q){
        int t;
        cin >> t;
        if(t == 0){
            ll u,v;
            cin >> u >> v;
            ll lca = hld.lca(u,v);
            cout << query(hld.node_query(0, u)) + query(hld.node_query(0, v)) - 2 * query(hld.node_query(0, lca)) << endl;
        }else{
            ll v,x;
            cin >> v >> x;
            nw[v] += x;
            x = nw[v];
            tr.set(hld[v], {1, x, x});
        }
    }
}
accuracy: 1
time_ms: 510
memory_kb: 47992
final_rank: 12

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

using ll = long long;

template <class T>
bool chmax(T& x, const T v) {
  if (x < v) {
    x = v;
    return true;
  } else {
    return false;
  }
}

template <typename T, typename F>
class lazysegmenttree {
  /*
  Copyright (c) 2024 0214sh7
  https://github.com/0214sh7/library/
  */
 public:
  int n, height;

  std::vector<T> dat;
  std::vector<F> lazy;
  std::vector<bool> lazy_flag;
  std::function<T(T, T)> calc;
  T identity;
  std::function<T(F, T)> action;
  std::function<F(F, F)> composition;
  F action_identity;

  void eval(int k) {
    if (!lazy_flag[k]) return;
    if (k < n - 1) {
      lazy[2 * k + 1] = composition(lazy[k], lazy[2 * k + 1]);
      lazy[2 * k + 2] = composition(lazy[k], lazy[2 * k + 2]);
      lazy_flag[2 * k + 1] = true;
      lazy_flag[2 * k + 2] = true;
    }
    dat[k] = action(lazy[k], dat[k]);
    lazy[k] = action_identity;
    lazy_flag[k] = false;
  }

 public:
  void init(int N, std::function<T(T, T)> func, T Identity,
            std::function<T(F, T)> Action, std::function<F(F, F)> Composition,
            F Action_identity) {
    n = 1;
    height = 1;
    while (n < N) {
      n *= 2;
      height++;
    };
    dat.resize(2 * n - 1);
    lazy.resize(2 * n - 1);
    lazy_flag.resize(2 * n - 1);
    for (int i = 0; i < 2 * n - 1; ++i) {
      dat[i] = Identity;
      lazy[i] = Action_identity;
      lazy_flag[i] = false;
    }
    calc = func;
    identity = Identity;
    action = Action;
    composition = Composition;
    action_identity = Action_identity;
  }

  lazysegmenttree(int N, std::function<T(T, T)> func, T Identity,
                  std::function<T(F, T)> Action,
                  std::function<F(F, F)> Composition, F Action_identity) {
    init(N, func, Identity, Action, Composition, Action_identity);
  }

  void set(std::vector<T> A) {
    if (n < (int)A.size()) {
      n = 1;
      height = 1;
      while (n < (int)A.size()) {
        n *= 2;
        height++;
      };
      dat.resize(2 * n - 1);
      lazy.resize(2 * n - 1);
      lazy_flag.resize(2 * n - 1);
    }
    for (int i = 0; i < 2 * n - 1; ++i) {
      dat[i] = identity;
      lazy[i] = action_identity;
      lazy_flag[i] = false;
    }
    for (unsigned i = 0; i < A.size(); i++) {
      dat[n - 1 + i] = A[i];
    }
    for (int i = n - 2; i >= 0; i--) {
      dat[i] = calc(dat[2 * i + 1], dat[2 * i + 2]);
    }
  }

  void update(int a, int b, F f) {
    a += n - 1;
    b += n - 1;
    for (int i = height - 1; i >= 0; i--) {
      if (((a + 1) >> i) > 0) {
        eval(((a + 1) >> i) - 1);
      }
      if ((b >> i) > 0) {
        eval((b >> i) - 1);
      }
    }

    int l = a, r = b - 1;
    while (a < b) {
      if (a % 2 == 0) {
        lazy[a] = composition(f, lazy[a]);
        lazy_flag[a] = true;
        a++;
      }
      a = (a - 1) / 2;

      if (b % 2 == 0) {
        b--;
        lazy[b] = composition(f, lazy[b]);
        lazy_flag[b] = true;
      }
      b = (b - 1) / 2;
    }

    while (l > 0) {
      l = (l - 1) / 2;
      eval(2 * l + 1);
      eval(2 * l + 2);
      dat[l] = calc(dat[2 * l + 1], dat[2 * l + 2]);
    }
    while (r > 0) {
      r = (r - 1) / 2;
      eval(2 * r + 1);
      eval(2 * r + 2);
      dat[r] = calc(dat[2 * r + 1], dat[2 * r + 2]);
    }
  }

  T query(int a, int b) {
    a += n - 1;
    b += n - 1;
    for (int i = height - 1; i >= 0; i--) {
      if (((a + 1) >> i) > 0) {
        eval(((a + 1) >> i) - 1);
      }
      if ((b >> i) > 0) {
        eval((b >> i) - 1);
      }
    }

    T L = identity, R = identity;
    while (a < b) {
      if (a % 2 == 0) {
        eval(a);
        L = calc(L, dat[a]);
        a++;
      }
      a = (a - 1) / 2;
      if (b % 2 == 0) {
        b--;
        eval(b);
        R = calc(dat[b], R);
      }
      b = (b - 1) / 2;
    }
    R = calc(L, R);
    return R;
  }
};

struct T {
  ll v, sign;
  T(ll v, ll sign) : v(v), sign(sign) {}
  T() : v(0), sign(0) {}
};

using F = int;

T calc(T a, T b) { return {a.v + b.v, a.sign + b.sign}; }

T action(F f, T x) { return {x.v + f * x.sign, x.sign}; }

F composition(F f, F g) { return f + g; }

T identity{0, 0};

int calc2(int a, int b) { return std::min(a, b); }

int action2(int f, int x) { return x; }

int composition2(int f, int g) { return g; }

std::ostream& operator<<(std::ostream& os, T t) { return os << t.v; }

template <class T, class F>
void dump(lazysegmenttree<T, F> segt) {
  for (int i = 0; i < segt.n; i++) {
    std::cerr << segt.query(i, i + 1) << (i == segt.n - 1 ? '\n' : ' ');
  }
}

int main() {
  int N, Q;
  std::cin >> N >> Q;

  std::vector nanachi(N, std::vector<int>());

  for (int i = 0; i < N - 1; i++) {
    int a, b;
    std::cin >> a >> b;
    nanachi[a].push_back(b);
  }

  std::vector<int> start(N), end(N), start2(N), end2(N);
  std::vector<T> tour;
  std::vector<int> tour2;

  auto rec = [&](auto self, int v) -> void {
    tour.emplace_back(0, 1);
    start[v] = tour.size();

    start2[v] = tour2.size();
    tour2.push_back(v);

    for (int w : nanachi[v]) {
      self(self, w);
      tour2.push_back(v);
    }

    end[v] = tour.size();
    tour.emplace_back(0, -1);

    end2[v] = tour2.size();
  };

  rec(rec, 0);

  int M = tour.size(), L = tour2.size();

  lazysegmenttree<T, F> segt(M, calc, identity, action, composition, 0);
  lazysegmenttree<int, int> segt2(L, calc2, N, action2, composition2, 0);

  segt.set(tour);
  segt2.set(tour2);

  while (Q--) {
    int t;
    std::cin >> t;
    if (t == 0) {
      int u, v;
      std::cin >> u >> v;

      if (u == v) {
        std::cout << 0 << '\n';
        continue;
      }

      if (start2[u] > start2[v]) {
        std::swap(u, v);
      }

      int c = segt2.query(start2[u], end2[v]);

      // std::cerr << "0: " << u << " " << v << " " << c << std::endl;

      T a = segt.query(start[c], start[u]), b = segt.query(start[c], start[v]);

      // std::cerr << "   " << a.v << " " << b.v << std::endl;

      std::cout << a.v + b.v << '\n';
    } else {
      int v, x;
      std::cin >> v >> x;

      // std::cerr << "1: " << v << " " << start[v] << " " << end[v] <<
      // std::endl;

      segt.update(start[v], end[v], x);

      // dump(segt);
    }
  }
}
accuracy: 1
time_ms: 370
memory_kb: 75168
final_rank: 14