Problem:
Do use segment tree
Given a tree with
n
(1 ≤ n ≤ 200,000)
nodes and a list of
q
(1 ≤ q ≤ 100,000)
queries,
process the queries in order and output a value for each output query.
The given tree is connected and each node on the tree has a weight
w
i
(-10,000 ≤ w
i
≤ 10,000)
.
Each query consists of a number
t
i
(t
i
= 1, 2)
, which indicates the type of the query , and  three numbers
a
i
,
b
i
and
c
i
(1 ≤ a
i
, b
i
≤ n, -10,000 ≤ c
i
≤ 10,000)
.
Depending on the query type, process one of the followings:
(
t
i
= 1
: modification query)
Change the weights of all nodes on the shortest path between
a
i
and
b
i
(both inclusive) to
c
i
.
(
t
i
= 2
: output query) 
First, create a list of weights on the shortest path between
a
i
and
b
i
(both inclusive) in order. After that, output the maximum sum of a non-empty continuous subsequence of the weights on the list.
c
i
is ignored for output queries.
Input
The first line contains two integers
n
and
q
.
 On the second line, there are
n
integers which indicate
w
1
,
w
2
, ... ,
w
n
.
Each of the following
n - 1
lines consists of two integers
s
i
and
e
i
(1 ≤ s
i
, e
i
≤ n)
,
which means that there is an edge between
s
i
and
e
i
.
Finally the following
q
lines give the list of queries, each of which contains four integers  in the format described above.
Queries  must be processed one by one from top to bottom.
Output
For each output query, output  the maximum sum in one line.
Sample Input 1
3 4
1 2 3
1 2
2 3
2 1 3 0
1 2 2 -4
2 1 3 0
2 2 2 0
Output for the Sample Input 1
6
3
-4
Sample Input 2
7 5
-8 5 5 5 5 5 5
1 2
2 3
1 4
4 5
1 6
6 7
2 3 7 0
2 5 2 0
2 4 3 0
1 1 1 -1
2 3 7 0
Output for the Sample Input 2
12
10
10
19
Sample Input 3
21 30
10 0 -10 -8 5 -5 -4 -3 1 -2 8 -1 -7 2 7 6 -9 -6 3 4 9
10 3
3 2
3 12
12 4
4 13
4 9
10 21
21 1
1 11
11 14
1 15
10 6
6 17
6 16
6 5
5 18
5 19
10 7
10 8
8 20
1 1 21 -10
1 3 19 10
2 1 13 0
1 4 18 8
1 5 17 -5
2 16 7 0
1 6 16 5
1 7 15 4
2 4 20 0
1 8 14 3
1 9 13 -1
2 9 18 0
1 10 12 2
1 11 11 -8
2 21 15 0
1 12 10 1
1 13 9 7
2 6 14 0
1 14 8 -2
1 15 7 -7
2 10 2 0
1 16 6 -6
1 17 5 9
2 12 17 0
1 18 4 6
1 19 3 -3
2 11 8 0
1 20 2 -4
1 21 1 -9
2 5 19 0
Output for the Sample Input 3
20
9
29
27
10
12
1
18
-2
-3

Submitted solutions:

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

template<typename T>
T bit_ceil(T x){
    T a = 1;
    while(a < x) a <<= 1;
    return a;
}
template<typename T>
int countr_zero(T x){
    if(x == 0) return 32;
    if constexpr(sizeof(T) == 4) return __builtin_ctz(x);
    else return __builtin_ctzll(x);
}
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, siz, log;
    vector<S> d;
    vector<F> lz;
    
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    lazy_segtree(const vector<S> &v) : n(v.size()) {
        siz = bit_ceil(n);
        log = countr_zero(siz);
        d = vector<S>(2*siz, e());
        lz = vector<F>(siz, id());
        for(int i = 0; i < n; i++) d[siz+i] = v[i];
        for(int i = siz-1; i >= 1; i--) update(i);
    }
    
    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 < siz) 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();
    }
    
    void set(int p, S x){
        p += siz;
        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){
        p += siz;
        for(int i = log; i >= 1; i--) push(p>>i);
        return d[p];
    }
    
    S prod(int l, int r){
        if(l == r) return e();
        l += siz; r += siz;
        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){
        p += siz;
        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){
        if(l == r) return;
        l += siz; r += siz;
        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<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<array<int, 2>> 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){
        E.push_back({u, v});
    }
    
    void build(const vector<S> &v){
        vector<vector<int>> G(n);
        for(auto i : E){
            G[i[0]].push_back(i[1]);
            G[i[1]].push_back(i[0]);
        }
        
        vector<int> sub_siz(n, 1);
        
        par[0] = -1;
        auto f1 = [&](auto self, int pos)->void {
            for(auto nex : G[pos]){
                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(auto nex : G[pos]){
                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(auto nex : G[pos]){
                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);
        for(int i = 0; i < n; i++) node_v[in[i]] = v[i];
        
        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], in[r]+1));
                else r_ans = op(node[1].prod(n-in[l]-1, n-in[r]), r_ans);
                return op(l_ans, r_ans);
            }
        }
    }
    
    S prod(int r){
        return node[0].prod(in[r], out[r]);
    }
    
    S get(int p){
        return node[0].get(in[p]);
    }
    
    void set(int p, const S &x){
        node[0].set(in[p], x);
        node[1].set(n-in[p]-1, x);
    }
    
    //!ここからは必須ではない（LCAなど）
    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, ma+1, x);
                node[1].apply(n-ma-1, n-mi, x);
                break;
            }
        }
    }
    
    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) で無向辺追加
    その後，頂点の値vectorを引数に build(vector<S> v) を呼び出す
    
    set(int p, S x) で，頂点pの値をxに変える
    prod(int l, int r) でlからrのパスクエリ
    prod(int r) で部分木クエリ
*/

struct S{
    long long l, r, m, s;
    int size;
    S() : l(0), r(0), m(0), size(0) {}
    S(int x) : l(x), r(x), m(x), s(x), size(1) {}
    S(long long a, long long b, long long c, long long d, int e) : l(a), r(b), m(c), s(d), size(e) {}
    S(const S &x) = default;
};
using F = long long;

constexpr F ID = 8e18;

S op(S l, S r) {
    if(l.size == 0) return r;
    if(r.size == 0) return l;
    S res = l;
    res.l = max(max(max(l.l, l.s), l.s+r.l), l.s+r.s);
    res.r = max(max(max(r.r, r.s), r.s+l.r), r.s+l.s);
    res.m = max(max(max(max(max(max(l.m, r.m), res.l), res.r), l.r), l.r+r.l), r.l);
    res.s = l.s + r.s;
    res.size = l.size + r.size;
    return res;
}
S e(){ return {-ID, -ID, -ID, 0ll, 0}; }
S mapping(F f, S x){
    if(f != ID) x.l = x.r = x.m = max(f, x.s = f*x.size);
    return x;
}
F composition(F f, F g){ return (f == ID ? g : f); }
F id(){ return ID; }

int main(){
    [[maybe_unused]] auto st = chrono::steady_clock::now();
    
    int n, q;
    cin >> n >> q;
    vector<S> A(n, {1});
    for(auto &i : A) cin >> i.l;
    for(auto &i : A) i.s = i.r = i.m = i.l;
    
    HLD<S, op, e, F, mapping, composition, id> seg(n);
    for(int i = 0; i < n-1; i++){
        int u, v;
        cin >> u >> v;
        u--; v--;
        seg.add_edge(u, v);
    }
    
    seg.build(A);
    
    assert(chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now()-st).count() < 800);
    
    while(q--){
        int t, u, v, x;
        cin >> t >> u >> v >> x;
        u--; v--;
        if(t == 1) seg.apply(u, v, x);
        else cout << seg.prod(u, v).m << '\n';
    }
}
accuracy: 1
time_ms: 1320
memory_kb: 99584
final_rank: 19

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

template<typename T>
T bit_ceil(T x){
    T a = 1;
    while(a < x) a <<= 1;
    return a;
}
template<typename T>
int countr_zero(T x){
    if(x == 0) return 32;
    if constexpr(sizeof(T) == 4) return __builtin_ctz(x);
    else return __builtin_ctzll(x);
}
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, siz, log;
    vector<S> d;
    vector<F> lz;
    
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(vector<S>(n, e())) {}
    lazy_segtree(const vector<S> &v) : n(v.size()) {
        siz = bit_ceil(n);
        log = countr_zero(siz);
        d = vector<S>(2*siz, e());
        lz = vector<F>(siz, id());
        for(int i = 0; i < n; i++) d[siz+i] = v[i];
        for(int i = siz-1; i >= 1; i--) update(i);
    }
    
    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 < siz) 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();
    }
    
    void set(int p, S x){
        p += siz;
        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){
        p += siz;
        for(int i = log; i >= 1; i--) push(p>>i);
        return d[p];
    }
    
    S prod(int l, int r){
        if(l == r) return e();
        l += siz; r += siz;
        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){
        p += siz;
        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){
        if(l == r) return;
        l += siz; r += siz;
        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<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<array<int, 2>> 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){
        E.push_back({u, v});
    }
    
    void build(const vector<S> &v){
        vector<vector<int>> G(n);
        for(auto i : E){
            G[i[0]].push_back(i[1]);
            G[i[1]].push_back(i[0]);
        }
        
        vector<int> sub_siz(n, 1);
        
        par[0] = -1;
        auto f1 = [&](auto self, int pos)->void {
            for(auto nex : G[pos]){
                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(auto nex : G[pos]){
                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(auto nex : G[pos]){
                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);
        for(int i = 0; i < n; i++) node_v[in[i]] = v[i];
        
        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], in[r]+1));
                else r_ans = op(node[1].prod(n-in[l]-1, n-in[r]), r_ans);
                return op(l_ans, r_ans);
            }
        }
    }
    
    S prod(int r){
        return node[0].prod(in[r], out[r]);
    }
    
    S get(int p){
        return node[0].get(in[p]);
    }
    
    void set(int p, const S &x){
        node[0].set(in[p], x);
        node[1].set(n-in[p]-1, x);
    }
    
    //!ここからは必須ではない（LCAなど）
    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, ma+1, x);
                node[1].apply(n-ma-1, n-mi, x);
                break;
            }
        }
    }
    
    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) で無向辺追加
    その後，頂点の値vectorを引数に build(vector<S> v) を呼び出す
    
    set(int p, S x) で，頂点pの値をxに変える
    prod(int l, int r) でlからrのパスクエリ
    prod(int r) で部分木クエリ
*/

struct S{
    long long l, r, m, s;
    int size;
    S() : l(0), r(0), m(0), size(0) {}
    S(int x) : l(x), r(x), m(x), s(x), size(1) {}
    S(long long a, long long b, long long c, long long d, int e) : l(a), r(b), m(c), s(d), size(e) {}
    S(const S &x) = default;
};
using F = long long;

constexpr F ID = 8e18;

S op(S l, S r) {
    if(l.size == 0) return r;
    if(r.size == 0) return l;
    S res = l;
    res.l = max(max(max(l.l, l.s), l.s+r.l), l.s+r.s);
    res.r = max(max(max(r.r, r.s), r.s+l.r), r.s+l.s);
    res.m = max(max(max(max(max(max(l.m, r.m), res.l), res.r), l.r), l.r+r.l), r.l);
    res.s = l.s + r.s;
    res.size = l.size + r.size;
    return res;
}
S e(){ return {-ID, -ID, -ID, 0ll, 0}; }
S mapping(F f, S x){
    if(f != ID) x.l = x.r = x.m = max(f, x.s = f*x.size);
    return x;
}
F composition(F f, F g){ return (f == ID ? g : f); }
F id(){ return ID; }

int main(){
    int n, q;
    cin >> n >> q;
    vector<S> A(n, {1});
    for(auto &i : A) cin >> i.l;
    for(auto &i : A) i.s = i.r = i.m = i.l;
    
    HLD<S, op, e, F, mapping, composition, id> seg(n);
    for(int i = 0; i < n-1; i++){
        int u, v;
        cin >> u >> v;
        u--; v--;
        seg.add_edge(u, v);
    }
    
    seg.build(A);
    
    while(q--){
        int t, u, v, x;
        cin >> t >> u >> v >> x;
        u--; v--;
        if(t == 1) seg.apply(u, v, x);
        else cout << seg.prod(u, v).m << '\n';
    }
}
accuracy: 1
time_ms: 1320
memory_kb: 99488
final_rank: 18

code_snippet: #include <iostream>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

typedef int int64;
template<class T> inline void checkmax(T & a, const T & b) { if( a < b ) a = b; }

const int MAXN = 4e5 + 10;
int val[MAXN];

struct S {
	int64 lmax, rmax, sum, inmax;
	S(int64 l = 0, int64 r = 0, int64 s = 0, int64 in = 0):lmax(l),rmax(r),sum(s),inmax(in) {}
	friend S comb(const S & a,  const S & b) {
		S r;
		r.sum = a.sum + b.sum;
		r.inmax = max( a.inmax, max(b.inmax, a.rmax+b.lmax ) );
		r.lmax = max(  a.lmax, a.sum + b.lmax);
		r.rmax = max(  b.rmax, b.sum + a.rmax);
		return r;
	}
	S sw() { return S(rmax,lmax,sum,inmax); }
	friend ostream & operator << (ostream & s, S a) {
		s<<"sum : "<<a.sum<<' '<<a.inmax<<' '<<a.lmax<<' '<<a.rmax<<endl;
		return s;
	}
};
struct SegTree{
	S s[MAXN*4];
	int L[MAXN*4], R[MAXN*4];
	bool pu[MAXN*4];
	int setval[MAXN*4];
	S buf[MAXN];
	int bufcnt;

	inline void update(int p) {
		if( L[p] == R[p] ) {
			s[p].sum = setval[p];
			s[p].lmax = s[p].rmax = s[p].inmax = setval[p]; // At Least One Elem
		}
		else {
			const int & ls = p*2, &rs = p*2+1;
			s[p] = comb(s[ls], s[rs]);
		}
	}
	inline void setp(int p, int64 v) {
		setval[p] = v;
		s[p].sum = (R[p] - L[p] + 1) * v;
		s[p].inmax = s[p].lmax = s[p].rmax = (v>=0) ? s[p].sum : v;
		pu[p] = true;
	}
	inline void pushdown(int p) {
		if( pu[p] ) {
			if( L[p] == R[p] ) ;
			else {
				setp(p*2, setval[p]);
				setp(p*2+1, setval[p]);
			}
			pu[p] = false;
		}
	}
	void init(int p, int l, int r) {
		L[p] = l, R[p] = r; pu[p] = false;
		if( l == r ) {
			setval[p] = val[l];
			update(p);
			return;
		}
		int mid = (l + r) / 2;
		init(p*2,  	l,	mid);
		init(p*2+1, mid+1,r);
		update(p);
	}

	void modify(int p, int l, int r , int64 v) {
		if( L[p] == l && R[p] == r ) {
			setp(p,v);
			return;
		}
		pushdown(p);
		int mid = (L[p] + R[p])/2;
		if( r <= mid ) modify(p*2, l, r, v);
		else if( l > mid ) modify(p*2+1, l, r, v);
		else modify(p*2, l, mid, v), modify(p*2+1, mid+1, r, v);
		update(p);
		return;
	}

	void _query(int p, int l, int r) {
		if( L[p] == l && R[p] == r ) {
			buf[bufcnt++] = s[p];
			return ;
		}
		pushdown(p);
		int mid = (L[p] + R[p])/2;
		if( r <= mid ) _query(p*2, l, r);
		else if( l > mid ) _query(p*2+1, l, r);
		else _query(p*2, l, mid ), _query(p*2+1, mid+1, r);
		update(p);
		return;
	}

	S query(int l, int r ) {
		bufcnt = 0;
		_query(1,l,r);
		S ret = buf[0];
		for (int i=1; i<bufcnt; i++)
			ret = comb(ret, buf[i]);
		return ret;
	}
}seg;

//=============================================================
int to[MAXN], nxt[MAXN], head[MAXN];
int son[MAXN], fa[MAXN], siz[MAXN], dep[MAXN], top[MAXN];
int id[MAXN];
int ec;
int cnt; //Need initialize
int root;
void init() { memset(head,-1, sizeof(head)); ec = 0; cnt = 0;}
inline void add(int u, int v) {
	to[ec] = v;
	nxt[ec] = head[u];
	head[u] = ec++;
}
void dfs(int u) {
	siz[u] = 1; son[u] = -1;
	for (int i = head[u]; i!=-1; i = nxt[i] ) {
		int &v = to[i];
		if( v != fa[u] ) {
			fa[v] = u;
			dep[v] = dep[u] + 1;
			dfs(v);
			siz[u] += siz[v];
			if( son[u] == -1 || siz[v] > siz[son[u]] ) 
				son[u] = v;
		}
	}
}
void maketree(int u, int tp) {
	id[u] = ++cnt; top[u] = tp;
	if( son[u] != -1) maketree(son[u], tp);
	for (int i=head[u]; i!=-1; i = nxt[i]) {
		if( to[i] != fa[u] && to[i] != son[u] ) 
			maketree(to[i], to[i]);
	}
}

int lca ( int u, int v ) {
	int fu = top[u], fv = top[v];
	while ( fu != fv ) {
		if( dep[fu] > dep[fv] ) 
			u = fa[fu], fu = top[u];
		else 
			v = fa[fv], fv = top[v];
	}
	return dep[u]<dep[v] ? u : v;
}
//=============================================================

void modi ( int u, int v , int64 vv) {
	int fu = top[u], fv = top[v];
	while ( fu != fv ) {
		if( dep[fu] > dep[fv] ) {
			seg.modify(1, id[fu], id[u], vv);
			u = fa[fu], fu = top[u];
		}
		else {
			seg.modify(1, id[fv], id[v], vv);
			v = fa[fv], fv = top[v];
		}
	}
	if( dep[u] < dep[v] )
		seg.modify(1, id[u], id[v], vv);
	else
		seg.modify(1, id[v], id[u], vv);
}

S buf1[MAXN], buf2[MAXN];
int64 getans (int u, int v ) {
	int c1 = 0, c2 = 0;
	int fu = top[u], fv = top[v];
	while (fu != fv) {
		if( dep[fu] > dep[fv] ) {
			buf1[c1++] = seg.query(id[fu], id[u]).sw();
			u = fa[fu], fu = top[u];
		}
		else {
			buf2[c2++] = seg.query(id[fv], id[v]);
			v = fa[fv], fv = top[v];
		}
	}
	if( dep[u] < dep[v] )
		buf2[c2++] = seg.query(id[u],id[v]);
	else
		buf1[c1++] = seg.query(id[v],id[u]).sw();

	for (int i = c2-1; i>=0; i--)
		buf1[c1++] = buf2[i];
	S ret = buf1[0];
	for (int i = 1; i<c1; i++) 
		ret = comb(ret, buf1[i]);
	return ret.inmax;
}
//=============================================================
int n,m;
int64 v[MAXN];
bool run() {
	if(scanf("%d%d",&n,&m) != 2) return false; 
	ec = cnt = 0;
	for (int i=1; i<=n; i++) head[i] = -1;
	init();
	for (int i=1; i<=n; i++) {
		scanf("%d",v+i);
	}
	for (int i=1; i<n; i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v); add(v,u);
	}
	root = (1+n)/2;
	fa[root] = -1;
	dfs(root);
	maketree(root,root);

	for (int i=1; i<=n; i++) 
		val[id[i]] = v[i];

	seg.init(1, 1, n);

	int t,a,b,c;
	for (int q = 0; q < m; q ++ ) {
		scanf("%d%d%d%d",&t,&a,&b,&c);
		if( t == 1 ) 
			modi(a,b,c);
		else 
			printf("%d\n",getans(a,b));
	}
	return true;
}

int main () {
	while( run() );
	return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 78000
final_rank: 16

code_snippet: #include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <climits>

#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)

using std::min;
using std::max;

const int N = 200000 + 10;

std::vector<int> neighbors[N];
int weight[N], n, m;

const int S = N << 2;
const int INF = 1 << 29;

#define L(u) ((u) << 1)
#define R(u) ((u) << 1 | 1)

int depth[N], pos[N], top[N], size[N], father[N], son[N], son_weight[N], temp_value[N];
int value[S], length[S], sum[S], leftmost[S], rightmost[S], flag[S];
int counter;

int queue[N];

void dfs_1(int root, int p) {
	queue[0] = root;
	father[root] = 0;
	depth[root] = 0;
	for (int head = 0, tail = 0; head <= tail; ++ head) {
		int u = queue[head];
		foreach(iter, neighbors[u]) {
			int v = *iter;
			if (v != father[u]) {
				queue[++ tail] = v;
				father[v] = u;
				depth[v] = depth[u] + 1;
			}
		}
	}
	for (int i = n; i >= 1; -- i) {
		int u = queue[i];
		size[u] = 1;
		int& pivot = son[u];
		foreach(iter, neighbors[u]) {
			int v = *iter;
			if (v != father[u]) {
				size[u] += size[v];
				if (pivot == 0 || size[v] > size[pivot]) {
					pivot = v;
				}
			}
		}
	}
	/*
	depth[u] = p == 0 ? 0 : depth[p] + 1;
	father[u] = p;
	size[u] = 1;
	int& pivot = son[u];
	foreach(iter, neighbors[u]) {
		int v = *iter;
		if (v != p) {
			dfs_1(v, u);
			size[u] += size[v];
			if (pivot == 0 || size[v] > size[pivot]) {
				pivot = v;
				son_weight[u] = weight[pivot];
			}
		}
	}
	*/
}

int property[N][2];

void dfs_2(int u, int t) {
	queue[1] = 1;
	property[1][0] = property[1][1] = 0;
	for (int length = 1; length > 0; ) {
		int u = queue[length];
		if (property[u][0] == 0) {
			pos[u] = ++ counter;
			top[u] = property[u][1];
			temp_value[counter] = weight[u];
			property[u][0] = 1;
		}
		if (property[u][0] == 1) {
			property[u][0] = 2;
			int v = son[u];
			if (v) {
				queue[++ length] = v;
				property[v][0] = 0;
				property[v][1] = top[u];
				continue;
			}
		}
		if (property[u][0] == 2) {
			length --;
			foreach(iter, neighbors[u]) {
				int v = *iter;
				if (v != father[u] && v != son[u]) {
					queue[++ length] = v;
					property[v][1] = v;
				}
			}
		}
	}
	/*
	pos[u] = ++ counter;
	top[u] = t;
	temp_value[counter] = weight[u];
	if (son[u]) {
		dfs_2(son[u], t);
	}
	foreach(iter, neighbors[u]) {
		int v = *iter;
		if (v != father[u] && v != son[u]) {
			dfs_2(v, v);
		}
	}
	*/
}

void update(int u) {
	sum[u] = sum[L(u)] + sum[R(u)];
	leftmost[u] = max(leftmost[L(u)], sum[L(u)] + leftmost[R(u)]);
	rightmost[u] = max(rightmost[R(u)], sum[R(u)] + rightmost[L(u)]);
	value[u] = max(value[L(u)], value[R(u)]);
	value[u] = max(value[u], rightmost[L(u)] + leftmost[R(u)]);
}

void build(int u, int l, int r) {
	length[u] = r - l + 1;
	flag[u] = INF;
	if (l == r) {
		value[u] = sum[u] = temp_value[l];
		leftmost[u] = rightmost[u] = sum[u];
	} else {
		int m = l + r >> 1;
		build(L(u), l, m);
		build(R(u), m + 1, r);
		update(u);
	}
}

void push_down(int u) {
	if (flag[u] != INF) {
		for (int i = 0; i < 2; ++ i) {
			int v = u << 1 | i;
			flag[v] = flag[u];
			sum[v] = flag[v] * length[v];
			value[v] = leftmost[v] = rightmost[v] = flag[v] >= 0 ? sum[v] : flag[v];
		}	
	}
	flag[u] = INF;
}

void insert(int u, int l, int r, int a, int b, int v) {
	if (a > r || b < l) {
		return;
	}
	if (a <= l && b >= r) {
		flag[u] = v;
		sum[u] = v * length[u];
		leftmost[u] = rightmost[u] = value[u] = sum[u] > 0 ? sum[u] : v;
	} else {
		push_down(u);
		int m = l + r >> 1;
		insert(L(u), l, m, a, b, v);
		insert(R(u), m + 1, r, a, b, v);
		update(u);
	}
}

struct Data {
	int sum, leftmost, rightmost, value;
	Data(int sum = 0, int leftmost = -INF, int rightmost = -INF, int value = -INF):
		sum(sum), leftmost(leftmost), value(value), rightmost(rightmost) {
	}
};

inline void update_max(int& a, int b) {
	a = a < b ? b : a;
}

void get_data(int u, int l, int r, int a, int b, Data& data) {
	if (a > r || b < l) {
		return;
	}
	if (a <= l && b >= r) {
		data = Data(sum[u], leftmost[u], rightmost[u], value[u]);
	} else {
		push_down(u);
		int m = l + r >> 1;
		Data left_data, right_data;
		get_data(L(u), l, m, a, b, left_data);
		get_data(R(u), m + 1, r, a, b, right_data);
		data.leftmost = max(left_data.leftmost, left_data.sum + right_data.leftmost);
		data.rightmost = max(right_data.rightmost, right_data.sum + left_data.rightmost);
		data.value = max(max(left_data.value, right_data.value), left_data.rightmost + right_data.leftmost);
		data.sum = left_data.sum + right_data.sum;
	}
}

void link_cut() {
	dfs_1(1, 0);
	counter = 0, dfs_2(1, 1);
	build(1, 1, n);
}

struct Triple {
	int a, b, c;
	Triple(int a = 0, int b = 0, int c = 0):
		a(a), b(b), c(c) {
	}
};

std::vector<Triple> blocks, right;
void get_blocks(int u, int v) {
	blocks.clear();
	right.clear();
	for (int du = top[u], dv = top[v]; du != dv; ) {
		if (depth[du] >= depth[dv]) {
			blocks.push_back(Triple(u, du, 0));
			u = father[du];
			du = top[u];
		} else {
			right.push_back(Triple(v, dv, 1));
			v = father[dv];
			dv = top[v];
		}
	}
	if (depth[u] < depth[v]) {
		blocks.push_back(Triple(v, u, 1));
	} else {
		blocks.push_back(Triple(u, v, 0));
	}
	for (int i = right.size() - 1; i >= 0; -- i) {
		blocks.push_back(right[i]);
	}
}

void cover(int u, int v, int c) {
	get_blocks(u, v);
	foreach(iter, blocks) {
		int u = (*iter).a;
		int v = (*iter).b;
		insert(1, 1, n, pos[v], pos[u], c);
	}
}

int query(int u, int v) {
	get_blocks(u, v);
	int answer = INT_MIN, now = 0;
	foreach(iter, blocks) {
		int u = (*iter).a;
		int v = (*iter).b;
		Data data;
		get_data(1, 1, n, pos[v], pos[u], data);
		int left = data.rightmost;
		int right = data.leftmost;
		if ((*iter).c == 1) {
			std::swap(left, right);
		}
		
		answer = max(answer, data.value);
		answer = max(answer, now + left);
		now = max(max(0, now + data.sum), right);
	}
	return answer;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d", weight + i);
	}
	for (int i = 1; i < n; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		neighbors[u].push_back(v);
		neighbors[v].push_back(u);
	}
	link_cut();
	while (m --) {
		int command, a, b, c;
		scanf("%d%d%d%d", &command, &a, &b, &c);
		if (command == 1) {
			cover(a, b, c);
		} else {
			printf("%d\n", query(a, b));
		}
	}
	return 0;
}
accuracy: 1
time_ms: 260
memory_kb: 42960
final_rank: 10

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class T> using VV = V<V<T>>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct S{
    ll len;
    ll sum;
    ll maxsum;
    ll maxsufsum;
    ll maxpresum;
};
using F = ll;
F composition(F f, F x){ return f != INF ? f : x; }
static S op(S l, S r){
    S res;
    res.len = l.len + r.len;
    res.maxsum = max(max(l.maxsum, r.maxsum), l.maxsufsum + r.maxpresum);
    res.sum = l.sum + r.sum;
    res.maxsufsum = max(l.maxsufsum + r.sum, r.maxsufsum);
    res.maxpresum = max(l.maxpresum, l.sum + r.maxpresum);
    return res;
}
S revS(S x){
    swap(x.maxpresum, x.maxsufsum);
    return x;
}
S mapping(F f, S x){
    if(f == INF) return x;
    x.sum = x.len * f;
    x.maxsum = x.maxsufsum = x.maxpresum = max(f, f * x.len);
    return x;
}
S e(){ return { 0, 0, -INF, -INF, -INF }; }
F id(){ return INF; }
struct LCNode {
    LCNode* c[2] = {0,0}, * p = 0;
    S a, sum;
    F lz = id();
    int rev = 0;
    void do_rev(){
        rev ^= 1;
        swap(c[0], c[1]);
        sum = revS(sum);
    }
    void prop(){
        if(rev) REP(t, 2) if(c[t]) c[t]->do_rev();
        REP(t, 2) if(c[t]) c[t]->app(lz);
        lz = id();
        rev = 0;
    }
    void app(F z){
        lz = composition(z, lz);
        a = mapping(z, a);
        sum = mapping(z, sum);
    }
    void agg(){
        sum = a;
        if(c[0]) sum = op(c[0]->sum, sum);
        if(c[1]) sum = op(sum, c[1]->sum);
    }
    int way(){
        if(!p) return -1;
        REP(t, 2) if(p->c[t] == this) return t;
        return -1;
    }
    void rot(){
        auto w = p;
        int x = way();
        if(w->way() != -1) w->p->c[w->way()] = this;
        p = w->p;
        w->c[x] = c[x^1];
        if(c[x^1]) c[x^1]->p = w;
        c[x^1] = w;
        w->p = this;
        w->agg();
        agg();
    }
    void propall(){
        if(way() >= 0) p->propall();
        prop();
    }
    void splay(){
        propall();
        for( ; way() >= 0; rot()) if(p->way() != -1)
            (way() == p->way() ? p : this)->rot();
    }
    void expose(){
        for(auto t=this; t; t = t->p) t->splay();
        for(auto t=this; t->p; t=t->p){
            t->p->c[1] = t;
            t->p->agg();
        }
        splay(); c[1] = 0; agg();
    }
    void evert(){ expose(), do_rev(); }
    void link(LCNode* r){ r->evert(), evert(), p = r; }
    void cut(){ expose(), c[0] = c[0]->p = 0; }
};

void testcase(){
    ll N, Q; cin >> N >> Q;
    V<ll> A(N); REP(i,N) cin >> A[i];
    V<LCNode> lct(N);
    REP(i,N) lct[i].a = lct[i].sum = { 1, A[i], A[i], A[i], A[i] };
    REP(i,N-1){
        ll u,v; cin >> u >> v; u--; v--;
        lct[u].link(&lct[v]);
    }
    REP(qi,Q){
        ll t, a, b, c; cin >> t >> a >> b >> c; a--; b--;
        lct[a].evert();
        lct[b].expose();
        if(t == 1){
            lct[b].app(c);
        } else {
            ll ans = lct[b].sum.maxsum;
            cout << ans << "\n";
        }
    }
}

int main(){
    cin.tie(0)->sync_with_stdio(0);
    testcase();
    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 28220
final_rank: 1

code_snippet: #define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2450"



#include <cstdint>
#include <cstddef>

namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa


#include <concepts>

namespace zawa {

namespace concepts {

template <class T>
concept Semigroup = requires {
    typename T::Element;
    { T::operation(std::declval<typename T::Element>(), std::declval<typename T::Element>()) } -> std::same_as<typename T::Element>;
};

} // namespace concepts

} // namespace zawa


namespace zawa {

namespace concepts {

template <class T>
concept Identitiable = requires {
    typename T::Element;
    { T::identity() } -> std::same_as<typename T::Element>;
};

template <class T>
concept Monoid = Semigroup<T> and Identitiable<T>;

} // namespace

} // namespace zawa


#include <vector>
#include <cassert>
#include <functional>
#include <type_traits>
#include <ostream>

namespace zawa {

template <concepts::Monoid Monoid>
class SegmentTree {
public:

    using VM = Monoid;

    using V = typename VM::Element;

    using OM = Monoid;

    using O = typename OM::Element;

    SegmentTree() = default;

    explicit SegmentTree(usize n) : m_n{ n }, m_dat(n << 1, VM::identity()) {}

    explicit SegmentTree(const std::vector<V>& dat) : m_n{ dat.size() }, m_dat(dat.size() << 1, VM::identity()) {
        for (usize i{} ; i < m_n ; i++) {
            m_dat[i + m_n] = dat[i];
        }
        for (usize i{m_n} ; i-- ; ) {
            m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]);
        }
    }

    [[nodiscard]] inline usize size() const noexcept {
        return m_n;
    }

    [[nodiscard]] V get(usize i) const {
        assert(i < size());
        return m_dat[i + m_n];
    }

    [[nodiscard]] V operator[](usize i) const {
        assert(i < size());
        return m_dat[i + m_n];
    }

    void operation(usize i, const O& value) {
        assert(i < size());
        i += size();
        m_dat[i] = OM::operation(m_dat[i], value);
        while (i = parent(i), i) {
            m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]);
        }
    }

    void assign(usize i, const V& value) {
        assert(i < size());
        i += size();
        m_dat[i] = value;
        while (i = parent(i), i) {
            m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]);
        }
    }

    [[nodiscard]] V product(u32 l, u32 r) const {
        assert(l <= r and r <= size());
        V L{ VM::identity() }, R{ VM::identity() };
        for (l += size(), r += size() ; l < r ; l = parent(l), r = parent(r)) {
            if (l & 1) {
                L = VM::operation(L, m_dat[l++]);
            }
            if (r & 1) {
                R = VM::operation(m_dat[--r], R);
            }
        }
        return VM::operation(L, R);
    }

    template <class F>
    requires std::predicate<F, V>
    [[nodiscard]] usize maxRight(usize l, const F& f) {
        assert(l < size());
        static_assert(std::is_convertible_v<decltype(f), std::function<bool(V)>>, "maxRight's argument f must be function bool(T)");
        assert(f(VM::identity()));
        usize res{l}, width{1};
        V prod{ VM::identity() };
        // 現在の見ている頂点の幅をwidthで持つ
        // 境界がある頂点を含む部分木の根を探す
        // (折り返す時は必要以上の幅を持つ根になるが、widthを持っているのでオーバーしない)
        for (l += size() ; res + width <= size() ; l = parent(l), width <<= 1) if (l & 1) {
            if (not f(VM::operation(prod, m_dat[l]))) break; 
            res += width;
            prod = VM::operation(prod, m_dat[l++]);
        }
        // 根から下って、境界を発見する
        while (l = left(l), width >>= 1) {
            if (res + width <= size() and f(VM::operation(prod, m_dat[l]))) {
                res += width;
                prod = VM::operation(prod, m_dat[l++]);
            } 
        }
        return res;
    }

    template <class F>
    requires std::predicate<F, V>
    [[nodiscard]] usize minLeft(usize r, const F& f) const {
        assert(r <= size());
        static_assert(std::is_convertible_v<decltype(f), std::function<bool(V)>>, "minLeft's argument f must be function bool(T)");
        assert(f(VM::identity()));
        usize res{r}, width{1};
        V prod{ VM::identity() };
        for (r += size() ; res >= width ; r = parent(r), width <<= 1) if (r & 1) {
            if (not f(VM::operation(m_dat[r - 1], prod))) break;
            res -= width;
            prod = VM::operation(prod, m_dat[--r]);
        }
        while (r = left(r), width >>= 1) {
            if (res >= width and f(VM::operation(m_dat[r - 1], prod))) {
                res -= width;
                prod = VM::operation(m_dat[--r], prod);
            }
        }
        return res;
    }

    friend std::ostream& operator<<(std::ostream& os, const SegmentTree& st) {
        for (usize i{1} ; i < 2 * st.size() ; i++) {
            os << st.m_dat[i] << (i + 1 == 2 * st.size() ? "" : " ");
        }
        return os;
    }

private:

    constexpr u32 left(u32 v) const {
        return v << 1;
    }

    constexpr u32 right(u32 v) const {
        return v << 1 | 1;
    }

    constexpr u32 parent(u32 v) const {
        return v >> 1;
    }

    usize m_n;

    std::vector<V> m_dat;
};

} // namespace zawa

#include <set>

namespace zawa {

namespace concepts {

template <class T, class U>
concept Powerable = requires {
    typename T::Element;
    { T::power(std::declval<typename T::Element>(), std::declval<U>()) }
        -> std::same_as<typename T::Element>;
};

template <class T>
concept EqualCompare = requires(T a, T b) {
    { a == b } -> std::convertible_to<bool>;
};

template <class T>
concept FastPowerableMonoid = Monoid<T> and Powerable<T, u64>;

} // namespace concepts

template <concepts::Monoid Monoid>
class AssignmentSegmentTree {
public:

    using VM = Monoid;

    using V = typename VM::Element;

    AssignmentSegmentTree() = default;

    explicit AssignmentSegmentTree(usize n) : m_seg{n}, m_dat(n, VM::identity()), m_ls{} {
        m_dat.shrink_to_fit();
        assert(n);
        m_ls.insert(0u);
        m_ls.insert(n);
    }

    explicit AssignmentSegmentTree(std::vector<V> dat) : m_seg{}, m_dat{dat}, m_ls{} {
        // dat: 区間の左端lにa_{l}^{r-l}, それ以外のiはidentity()にする -> セグ木にこれをのせる
        // m_dat: 区間の左端lにa_{l}, それ以外のiはidentity()にする
        m_dat.shrink_to_fit();
        if constexpr (concepts::EqualCompare<V>) {
            for (usize i{}, j{} ; i < m_dat.size() ; ) {
                while (j < dat.size() and dat[i] == dat[j]) j++;
                m_ls.insert(i);
                dat[i] = power(m_dat[i], j - i);
                for ( ; ++i < j ; dat[i] = m_dat[i] = VM::identity()) ;
            }
        }
        else {
            for (usize i{} ; i < m_dat.size() ; i++) m_ls.insert(i);
        }
        m_ls.insert(dat.size());
        m_seg = decltype(m_seg){dat};
    }

    [[nodiscard]] inline usize size() const noexcept {
        return m_dat.size();
    }

    [[nodiscard]] V product(usize l, usize r) const {
        assert(l <= r and r <= size());
        if (l == r) return VM::identity();
        const auto second_l = m_ls.upper_bound(l);
        const auto first_l = std::prev(second_l);
        if (second_l != m_ls.end() and r <= *second_l) { // 一つの区間に含まれている
            return power(m_dat[*first_l], r - l);
        }
        const auto last_l = std::prev(m_ls.upper_bound(r));
        V res = VM::operation(
                power(m_dat[*first_l], *second_l - l),
                m_seg.product(*second_l, *last_l)
                );
        if (r == *last_l) return res;
        return VM::operation(res, power(m_dat[*last_l], r - *last_l));
    }

    void assign(usize l, usize r, V v) {
        assert(l <= r and r <= m_dat.size());
        if (l == r) return;
        // assert(*it_l < n);
        auto it_l = std::prev(m_ls.upper_bound(l)), it_r = std::prev(m_ls.upper_bound(r)); 
        if (*it_l < l) m_seg.assign(*it_l, power(m_dat[*it_l], l - *it_l));
        m_seg.assign(l, power(v, r - l));
        if (*it_r < r and r < m_dat.size()) {
            m_dat[r] = m_dat[*it_r];
            m_seg.assign(r, power(m_dat[r], *std::next(it_r) - r));
            m_ls.insert(r);
        }
        m_dat[l] = v;
        for (it_l++ ; *it_l < r ; it_l = m_ls.erase(it_l)) {
            m_seg.assign(*it_l, VM::identity());
            m_dat[*it_l] = VM::identity();
        }
        m_ls.insert(l);
    }

private:

    SegmentTree<VM> m_seg;

    std::vector<V> m_dat;

    std::set<usize> m_ls; 

    static V power(V v, u32 p) requires concepts::FastPowerableMonoid<VM> {
        return VM::power(v, p);
    }

    static V power(V v, u32 p) {
        V res{VM::identity()};
        while (p) {
            if (p & 1) res = VM::operation(res, v);
            v = VM::operation(v, v);
            p >>= 1; 
        }
        return res;
    }
};

} // namespace zawa


#include <algorithm>
#include <cmath>
#include <limits>
#include <utility>

namespace zawa {

template <class V>
class HeavyLightDecomposition {
public:

    static constexpr V Invalid() noexcept {
        return INVALID;
    }

    HeavyLightDecomposition() = default;

    HeavyLightDecomposition(std::vector<std::vector<V>> T, V root = 0u) 
        : n_{T.size()}, par_(n_), top_(n_), idx_(n_), 
        inv_(n_), size_(n_, usize{1}), dep_(n_) {

            auto dfs1{[&](auto dfs, V v, V p, usize d) -> usize {
                par_[v] = p;
                dep_[v] = d;
                if (p != INVALID) {
                    for (u32 i{} ; i + 1 < T[v].size() ; i++) if (T[v][i] == p) {
                        std::swap(T[v][i], T[v].back());
                        break;
                    }
                    assert(T[v].back() == p);
                    T[v].pop_back();
                }
                for (V x : T[v]) {
                    size_[v] += dfs(dfs, x, v, d + 1);
                }
                for (u32 i{1} ; i < T[v].size() ; i++) if (size_[T[v][0]] < size_[T[v][i]]) {
                    std::swap(T[v][0], T[v][i]);
                }
                return size_[v];
            }};

            auto dfs2{[&](auto dfs, V v, V idx, V top) -> V {
                idx_[v] = idx++;
                inv_[idx_[v]] = v;
                top_[v] = top;
                if (T[v].size()) {
                    idx = dfs(dfs, T[v][0], idx, top);
                    for (u32 i{1} ; i < T[v].size() ; i++) {
                        idx = dfs(dfs, T[v][i], idx, T[v][i]);
                    }
                }
                return idx;
            }};

            dfs1(dfs1, root, INVALID, 0u);
            dfs2(dfs2, root, 0u, root);
        }

    inline usize size() const noexcept {
        return n_;
    }

    usize size(V v) const noexcept {
        assert(v < (V)size());
        return size_[v];
    }

    usize depth(V v) const noexcept {
        assert(v < (V)size());
        return dep_[v];
    }

    V parent(V v) const noexcept {
        assert(v < (V)size());
        return par_[v];
    }

    V index(V v) const noexcept {
        assert(v < (V)size());
        return idx_[v];
    }

    V operator[](V v) const noexcept {
        assert(v < (V)size());
        return idx_[v];
    }

    std::vector<std::pair<V, V>> decomp(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        std::vector<std::pair<V, V>> res, ser;
        while (top_[s] != top_[t]) {
            if (dep_[top_[s]] >= dep_[top_[t]]) {
                res.emplace_back(s, top_[s]);
                s = top_[s];
                if (par_[s] != INVALID) s = par_[s];
            }
            else {
                ser.emplace_back(top_[t], t);
                t = top_[t];
                if (par_[t] != INVALID) t = par_[t];
            }
        }
        res.emplace_back(s, t);
        std::reverse(ser.begin(), ser.end());
        res.insert(res.end(), ser.begin(), ser.end()); 
        return res;
    }

    std::vector<std::pair<V, V>> operator()(V s, V t) const {
        return decomp(s, t);
    }

    V lca(V u, V v) const {
        assert(u < (V)size());
        assert(v < (V)size());
        while (top_[u] != top_[v]) {
            if (dep_[top_[u]] >= dep_[top_[v]]) {
                u = top_[u];
                if (par_[u] != INVALID) u = par_[u];
            }
            else {
                v = top_[v];
                if (par_[v] != INVALID) v = par_[v];
            }
        }
        return (dep_[u] <= dep_[v] ? u : v);
    }

    // pはvの祖先か？
    bool isAncestor(V v, V p) {
        assert(v < size());
        assert(p < size());
        if (dep_[v] < dep_[p]) return false;
        while (v != INVALID and top_[v] != top_[p]) {
            v = par_[top_[v]];
        }
        return v != INVALID;
    }

    V levelAncestor(V v, usize step) const {
        assert(v < (V)size());
        if (step > dep_[v]) return INVALID;
        while (true) {
            usize dist{dep_[v] - dep_[top_[v]]};
            if (dist >= step) break;
            step -= dist + 1;
            v = par_[top_[v]];
        }
        step = (dep_[v] - dep_[top_[v]]) - step;
        return inv_[idx_[top_[v]] + step];
    }

    V jump(V s, V t, usize step) const {
        assert(s < (V)size());
        assert(t < (V)size());
        V uu{INVALID}, vv{INVALID};
        usize d{};
        for (auto [u, v] : decomp(s, t)) {
            usize dist{std::max(dep_[u], dep_[v]) - std::min(dep_[u], dep_[v])};
            if (dist >= step) {
                uu = u;
                vv = v;
                d = dist;
                break;
            }
            step -= dist + 1;
        }
        if (uu == INVALID) return INVALID;
        if (dep_[uu] <= dep_[vv]) {
            return inv_[idx_[uu] + step];
        }
        else {
            return inv_[idx_[vv] + (d - step)];
        }
    }

    usize distance(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        usize res{};
        for (auto [u, v] : decomp(s, t)) {
            if (dep_[u] > dep_[v]) std::swap(u, v);
            res += dep_[v] - dep_[u];
        }
        return res;
    }

private:
    static constexpr V INVALID{static_cast<V>(-1)};
    usize n_{};
    std::vector<V> par_{}, top_{}, idx_{}, inv_{};
    std::vector<usize> size_{}, dep_{};
};

} // namespace zawa

#include <optional>

namespace zawa {

template <std::totally_ordered T>
class SubarraySumMax {
public:

    SubarraySumMax() = default;

    explicit SubarraySumMax(T v) : m_ans{v}, m_sum{v}, m_pref{v}, m_suf{v}, m_entire{true} {}

    SubarraySumMax(T ans, T sum, T pref, T suf, bool entire) : m_ans{ans}, m_sum{sum}, m_pref{pref}, m_suf{suf}, m_entire{entire} {}

    inline T ans() const {
        return m_ans;
    }

    inline T sum() const {
        return m_sum;
    }

    inline T pref() const {
        return m_pref;
    }

    inline T suf() const {
        return m_suf;
    }

    inline bool entire() const {
        return m_entire;
    }

    static SubarraySumMax<T> merge(const SubarraySumMax<T>& lhs, const SubarraySumMax<T>& rhs) {
        T sum = lhs.sum() + rhs.sum();
        T pref = std::max(lhs.pref(), lhs.sum() + rhs.pref());
        T suf = std::max(rhs.suf(), lhs.suf() + rhs.sum());
        T ans = std::max({lhs.ans(), rhs.ans(), lhs.suf() + rhs.pref(), sum});
        bool entire = (ans == sum);
        return {ans, sum, pref, suf, entire};
    }

private:

    T m_ans{}, m_sum{}, m_pref{}, m_suf{};

    bool m_entire{};
};

template <std::totally_ordered T>
struct SubarraySumMaxMonoid {

    using Element = std::optional<SubarraySumMax<T>>;

    static Element identity() {
        return std::nullopt;
    }

    static Element operation(const Element& L, const Element& R) {
        if (!L) return R;
        if (!R) return L;
        return Element::value_type::merge(L.value(), R.value());
    }

    static Element convert(T v) {
        return Element{v};
    }
};

} // namespace zawa


namespace zawa {

template <concepts::Monoid M>
struct ReverseOrder {

    using Element = M::Element;
    
    static Element identity() {
        return M::identity();
    }

    static Element operation(const Element& L, const Element& R) {
        return M::operation(R, L);
    }

};

} // namespace zawa

#include <iostream>
using namespace std;
using namespace zawa;
using M = SubarraySumMaxMonoid<long long>;

int main() {
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int N, Q;
    cin >> N >> Q;
    vector<int> A(N);
    for (int i = 0 ; i < N ; i++) cin >> A[i];
    vector<vector<int>> g(N);
    for (int i = 0 ; i < N - 1 ; i++) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    HeavyLightDecomposition hld{g};
    vector<M::Element> init(N);
    for (int i = 0 ; i < N ; i++) init[hld[i]] = M::convert(A[i]);
    AssignmentSegmentTree<M> seg{init};
    AssignmentSegmentTree<ReverseOrder<M>> ges{init};
    while (Q--) {
        int T;
        cin >> T;
        int a, b, c;
        cin >> a >> b >> c;
        a--; b--;
        if (T == 1) {
            for (auto [s, t] : hld(a, b)) {
                s = hld[s];
                t = hld[t];
                if (s > t) swap(s, t);
                seg.assign(s, t + 1, M::convert(c));
                ges.assign(s, t + 1, M::convert(c));
            }
        }
        else if (T == 2) {
            M::Element pd = M::identity();
            for (auto [s, t] : hld(a, b)) {
                s = hld[s];
                t = hld[t];
                if (s <= t) pd = M::operation(pd, seg.product(s, t + 1));
                else pd = M::operation(pd, ges.product(t, s + 1));
            }
            assert(pd);
            cout << pd->ans() << '\n';
        }
        else assert(false);
    }
}
accuracy: 1
time_ms: 1220
memory_kb: 138508
final_rank: 20

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,0,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==0||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==0)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
    void pf()
    {
        printf("%lld %lld %lld %lld\n",lsum,rsum,msum,sum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(a.msum,b.msum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
      //  printf("%d ",a[fp[l]]);
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int flag=1;
  //  if(u==9&&v==18)flag=0;
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2;
    while(f1!=f2)
    {
      // if(!flag)  printf("f1=%d f2=%d %d %d\n",f1,f2,u,v);
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
           // tmp.pf();
            v=fa[f2];f2=top[v];
          //  swap(f1,f2);
          //  swap(u,v);
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                node tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
           // tmp.pf();
            u=fa[f1];f1=top[u];
        }
        if(!first1&&!flag)tmp1.pf();
        if(!first2&&!flag)tmp2.pf();
    }
  //  printf("fir1=%d fir2=%d:\n",first1,first2);

    if(dep[u]>dep[v])
    {//puts("sdf");
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            node tmp=query(p[v],p[u],1,pos,1);
            swap(tmp.lsum,tmp.rsum);
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
 //   if(!first1&&!flag)tmp1.pf();
   // if(!first2&&!flag)tmp2.pf();
   // tmp.pf();
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
  //      printf("pos=%d %d %d %d %d\n",top[5],top[6],top[10],top[21],top[19]);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
    //        for(int i=1;i<=n;i++)printf("i=%d:%lld ",i,lca(i,i).sum);puts("");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 39620
final_rank: 4

code_snippet: //#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,0,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==0||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==0)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(a.msum,b.msum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L==l&&r==R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)update(L,R,c,lson);
    else if(L>m)update(L,R,c,rson);
    else
    {
       update(L,m,c,lson);
       update(m+1,R,c,rson);
    }
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2,tmp;
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
            v=fa[f2];f2=top[v];
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
            u=fa[f1];f1=top[u];
        }
    }

    if(dep[u]>dep[v])
    {
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            tmp=query(p[v],p[u],1,pos,1);
            tmp.sp();
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 39708
final_rank: 5

code_snippet: #pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 200000 + 10;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int v, nxt;
	Edge(int v = 0, int nxt = 0): v(v), nxt(nxt) {}
};

int ecnt, head[maxn];
Edge edges[maxn * 2];

void AddEdge(int u, int v) {
	edges[ecnt] = Edge(v, head[u]);
	head[u] = ecnt++;
}

int n, q, w[maxn];

int sz[maxn], fa[maxn], son[maxn], dep[maxn];

void dfs(int u) {
	sz[u] = 1; son[u] = 0;
	for(int i = head[u]; ~i; i = edges[i].nxt) {
		int v = edges[i].v;
		if(v == fa[u]) continue;
		fa[v] = u;
		dep[v] = dep[u] + 1;
		dfs(v);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
}

int top[maxn], id[maxn], pos[maxn], tot;

void dfs2(int u, int tp) {
	id[u] = ++tot;
	pos[tot] = u;
	top[u] = tp;
	if(!son[u]) return;
	dfs2(son[u], tp);
	for(int i = head[u]; ~i; i = edges[i].nxt) {
		int v = edges[i].v;
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}

struct Node
{
	int sum, pre, suf, sub;
	Node() {}
	Node(int a, int b, int c, int d): sum(a), pre(b), suf(c), sub(d) {}
	Node operator + (const Node& t) const {
		Node ans;
		ans.sum = sum + t.sum;
		ans.pre = max(pre, sum + t.pre);
		ans.suf = max(t.suf, t.sum + suf);
		ans.sub = max(max(sub, t.sub), suf + t.pre);
		return ans;
	}
};

Node T[maxn << 2];
int set[maxn << 2];

void build(int o, int L, int R) {
	if(L == R) {
		T[o].sum = T[o].pre = T[o].suf = T[o].sub = w[pos[L]];
		return;
	}
	int M = (L + R) / 2;
	build(o<<1, L, M);
	build(o<<1|1, M+1, R);
	T[o] = T[o<<1] + T[o<<1|1];
}

void pushdown(int o, int L, int R) {
	if(set[o] != INF) {
		set[o<<1] = set[o<<1|1] = set[o];
		int lc = o<<1, rc = o<<1|1;
		int M = (L + R) / 2;
		T[lc].sum = set[o] * (M - L + 1);
		T[rc].sum = set[o] * (R - M);
		T[lc].pre = T[lc].suf = T[lc].sub = set[o] > 0 ? T[lc].sum : set[o];
		T[rc].pre = T[rc].suf = T[rc].sub = set[o] > 0 ? T[rc].sum : set[o];
		set[o] = INF;
	}
}

void update(int o, int L, int R, int qL, int qR, int v) {
	if(qL <= L && R <= qR) {
		set[o] = v;
		T[o].sum = (R - L + 1) * v;
		T[o].pre = T[o].suf = T[o].sub = v > 0 ? T[o].sum : v;
		return;
	}
	pushdown(o, L, R);
	int M = (L + R) / 2;
	if(qL <= M) update(o<<1, L, M, qL, qR, v);
	if(qR > M) update(o<<1|1, M+1, R, qL, qR, v);
	T[o] = T[o<<1] + T[o<<1|1];
}

void UPDATE(int u, int v, int val) {
	int t1 = top[u], t2 = top[v];
	while(t1 != t2) {
		if(dep[t1] < dep[t2]) { swap(u, v); swap(t1, t2); }
		update(1, 1, n, id[t1], id[u], val);
		u = fa[t1]; t1 = top[u];
	}
	if(dep[u] > dep[v]) swap(u, v);
	update(1, 1, n, id[u], id[v], val);
}

Node query(int o, int L, int R, int qL, int qR) {
	if(qL <= L && R <= qR) return T[o];
	pushdown(o, L, R);
	int M = (L + R) / 2;
	if(qR <= M) return query(o<<1, L, M, qL, qR);
	else if(qL > M) return query(o<<1|1, M+1, R, qL, qR);
	else return query(o<<1, L, M, qL, qR) + query(o<<1|1, M+1, R, qL, qR);
}

void updateans(Node& q, bool& flag, int L, int R) {
	if(!flag) { q = query(1, 1, n, L, R); flag = true; }
	else q = query(1, 1, n, L, R) + q;
}

int QUERY(int u, int v) {
	Node q1, q2;
	bool flag1 = false, flag2 = false;
	int t1 = top[u], t2 = top[v];
	while(t1 != t2) {
		if(dep[t1] > dep[t2]) {
			updateans(q1, flag1, id[t1], id[u]);
			u = fa[t1]; t1 = top[u];
		} else {
			updateans(q2, flag2, id[t2], id[v]);;
			v = fa[t2]; t2 = top[v];
		}
	}
	if(dep[u] > dep[v]) updateans(q1, flag1, id[v], id[u]);
	else updateans(q2, flag2, id[u], id[v]);
	if(!flag1) return q2.sub;
	if(!flag2) return q1.sub;
	swap(q1.pre, q1.suf);
	return (q1 + q2).sub;
}

int main()
{
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%d", w + i);

	ecnt = 0;
	memset(head, -1, sizeof(head));
	for(int i = 1; i < n; i++) {
		int u, v; scanf("%d%d", &u, &v);
		AddEdge(u, v); AddEdge(v, u);
	}

	dfs(1);
	tot = 0;
	dfs2(1, 1);
	
	memset(set, 0x3f, sizeof(set));
	build(1, 1, n);

	while(q--) {
		int op, a, b, c; scanf("%d%d%d%d", &op, &a, &b, &c);
		if(op == 1) {
			UPDATE(a, b, c);
		} else {
			printf("%d\n", QUERY(a, b));
		}
	}

	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 36060
final_rank: 7

code_snippet: #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 200000 + 10;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int v, nxt;
	Edge(int v = 0, int nxt = 0): v(v), nxt(nxt) {}
};

int ecnt, head[maxn];
Edge edges[maxn * 2];

void AddEdge(int u, int v) {
	edges[ecnt] = Edge(v, head[u]);
	head[u] = ecnt++;
}

int n, q, w[maxn];

int sz[maxn], fa[maxn], son[maxn], dep[maxn];

void dfs(int u) {
	sz[u] = 1; son[u] = 0;
	for(int i = head[u]; ~i; i = edges[i].nxt) {
		int v = edges[i].v;
		if(v == fa[u]) continue;
		fa[v] = u;
		dep[v] = dep[u] + 1;
		dfs(v);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
}

int top[maxn], id[maxn], pos[maxn], tot;

void dfs2(int u, int tp) {
	id[u] = ++tot;
	pos[tot] = u;
	top[u] = tp;
	if(!son[u]) return;
	dfs2(son[u], tp);
	for(int i = head[u]; ~i; i = edges[i].nxt) {
		int v = edges[i].v;
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}

struct Node
{
	int sum, pre, suf, sub;
	Node() {}
	Node(int a, int b, int c, int d): sum(a), pre(b), suf(c), sub(d) {}
	Node operator + (const Node& t) const {
		Node ans;
		ans.sum = sum + t.sum;
		ans.pre = max(pre, sum + t.pre);
		ans.suf = max(t.suf, t.sum + suf);
		ans.sub = max(max(sub, t.sub), suf + t.pre);
		return ans;
	}
};

Node T[maxn << 2];
int set[maxn << 2];

void build(int o, int L, int R) {
	if(L == R) {
		T[o].sum = T[o].pre = T[o].suf = T[o].sub = w[pos[L]];
		return;
	}
	int M = (L + R) / 2;
	build(o<<1, L, M);
	build(o<<1|1, M+1, R);
	T[o] = T[o<<1] + T[o<<1|1];
}

void pushdown(int o, int L, int R) {
	if(set[o] != INF) {
		set[o<<1] = set[o<<1|1] = set[o];
		int lc = o<<1, rc = o<<1|1;
		int M = (L + R) / 2;
		T[lc].sum = set[o] * (M - L + 1);
		T[rc].sum = set[o] * (R - M);
		T[lc].pre = T[lc].suf = T[lc].sub = set[o] > 0 ? T[lc].sum : set[o];
		T[rc].pre = T[rc].suf = T[rc].sub = set[o] > 0 ? T[rc].sum : set[o];
		set[o] = INF;
	}
}

void update(int o, int L, int R, int qL, int qR, int v) {
	if(qL <= L && R <= qR) {
		set[o] = v;
		T[o].sum = (R - L + 1) * v;
		T[o].pre = T[o].suf = T[o].sub = v > 0 ? T[o].sum : v;
		return;
	}
	pushdown(o, L, R);
	int M = (L + R) / 2;
	if(qL <= M) update(o<<1, L, M, qL, qR, v);
	if(qR > M) update(o<<1|1, M+1, R, qL, qR, v);
	T[o] = T[o<<1] + T[o<<1|1];
}

void UPDATE(int u, int v, int val) {
	int t1 = top[u], t2 = top[v];
	while(t1 != t2) {
		if(dep[t1] < dep[t2]) { swap(u, v); swap(t1, t2); }
		update(1, 1, n, id[t1], id[u], val);
		u = fa[t1]; t1 = top[u];
	}
	if(dep[u] > dep[v]) swap(u, v);
	update(1, 1, n, id[u], id[v], val);
}

Node query(int o, int L, int R, int qL, int qR) {
	if(qL <= L && R <= qR) return T[o];
	pushdown(o, L, R);
	int M = (L + R) / 2;
	if(qR <= M) return query(o<<1, L, M, qL, qR);
	else if(qL > M) return query(o<<1|1, M+1, R, qL, qR);
	else return query(o<<1, L, M, qL, qR) + query(o<<1|1, M+1, R, qL, qR);
}

void updateans(Node& q, bool& flag, int L, int R) {
	if(!flag) { q = query(1, 1, n, L, R); flag = true; }
	else q = query(1, 1, n, L, R) + q;
}

int QUERY(int u, int v) {
	Node q1, q2;
	bool flag1 = false, flag2 = false;
	int t1 = top[u], t2 = top[v];
	while(t1 != t2) {
		if(dep[t1] > dep[t2]) {
			updateans(q1, flag1, id[t1], id[u]);
			u = fa[t1]; t1 = top[u];
		} else {
			updateans(q2, flag2, id[t2], id[v]);;
			v = fa[t2]; t2 = top[v];
		}
	}
	if(dep[u] > dep[v]) updateans(q1, flag1, id[v], id[u]);
	else updateans(q2, flag2, id[u], id[v]);
	if(!flag1) return q2.sub;
	if(!flag2) return q1.sub;
	swap(q1.pre, q1.suf);
	return (q1 + q2).sub;
}

int main()
{
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%d", w + i);

	ecnt = 0;
	memset(head, -1, sizeof(head));
	for(int i = 1; i < n; i++) {
		int u, v; scanf("%d%d", &u, &v);
		AddEdge(u, v); AddEdge(v, u);
	}

	dfs(1);
	tot = 0;
	dfs2(1, 1);
	
	memset(set, 0x3f, sizeof(set));
	build(1, 1, n);

	while(q--) {
		int op, a, b, c; scanf("%d%d%d%d", &op, &a, &b, &c);
		if(op == 1) {
			UPDATE(a, b, c);
		} else {
			printf("%d\n", QUERY(a, b));
		}
	}

	return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 35872
final_rank: 9

code_snippet: #pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,0,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==0||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==0)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(a.msum,b.msum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L==l&&r==R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)update(L,R,c,lson);
    else if(L>m)update(L,R,c,rson);
    else
    {
       update(L,m,c,lson);
       update(m+1,R,c,rson);
    }
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2,tmp;
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
            v=fa[f2];f2=top[v];
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
            u=fa[f1];f1=top[u];
        }
    }

    if(dep[u]>dep[v])
    {
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            tmp=query(p[v],p[u],1,pos,1);
            tmp.sp();
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 39468
final_rank: 2

code_snippet: #pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,0,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==0||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==0)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(a.msum,b.msum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2,tmp;
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
            v=fa[f2];f2=top[v];
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
            u=fa[f1];f1=top[u];
        }
    }

    if(dep[u]>dep[v])
    {
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            tmp=query(p[v],p[u],1,pos,1);
            tmp.sp();
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 39760
final_rank: 6

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,0,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==0||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==0)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(a.msum,b.msum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2,tmp;
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
            v=fa[f2];f2=top[v];
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
            u=fa[f1];f1=top[u];
        }
    }

    if(dep[u]>dep[v])
    {
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            tmp=query(p[v],p[u],1,pos,1);
            tmp.sp();
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 39484
final_rank: 3

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 500010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,-1,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==-1||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==-1)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
    void pf()
    {
        printf("%lld %lld %lld %lld\n",lsum,rsum,msum,sum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(a.msum,b.msum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
      //  printf("%d ",a[fp[l]]);
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int flag=1;
  //  if(u==9&&v==18)flag=0;
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2;
    while(f1!=f2)
    {
      // if(!flag)  printf("f1=%d f2=%d %d %d\n",f1,f2,u,v);
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
           // tmp.pf();
            v=fa[f2];f2=top[v];
          //  swap(f1,f2);
          //  swap(u,v);
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                node tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
           // tmp.pf();
            u=fa[f1];f1=top[u];
        }
        if(!first1&&!flag)tmp1.pf();
        if(!first2&&!flag)tmp2.pf();
    }
  //  printf("fir1=%d fir2=%d:\n",first1,first2);

    if(dep[u]>dep[v])
    {//puts("sdf");
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            node tmp=query(p[v],p[u],1,pos,1);
            swap(tmp.lsum,tmp.rsum);
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
 //   if(!first1&&!flag)tmp1.pf();
   // if(!first2&&!flag)tmp2.pf();
   // tmp.pf();
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
  //      printf("pos=%d %d %d %d %d\n",top[5],top[6],top[10],top[21],top[19]);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
    //        for(int i=1;i<=n;i++)printf("i=%d:%lld ",i,lca(i,i).sum);puts("");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 52884
final_rank: 11

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,-1,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==-1||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==-1)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    int lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
    void pf()
    {
        printf("%lld %lld %lld %lld\n",lsum,rsum,msum,sum);
    }
}s[N<<2];
int col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(max(a.msum,b.msum),a.sum+b.sum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
      //  printf("%d ",a[fp[l]]);
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int flag=1;
  //  if(u==9&&v==18)flag=0;
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2;
    while(f1!=f2)
    {
      // if(!flag)  printf("f1=%d f2=%d %d %d\n",f1,f2,u,v);
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
           // tmp.pf();
            v=fa[f2];f2=top[v];
          //  swap(f1,f2);
          //  swap(u,v);
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                node tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
           // tmp.pf();
            u=fa[f1];f1=top[u];
        }
        if(!first1&&!flag)tmp1.pf();
        if(!first2&&!flag)tmp2.pf();
    }
  //  printf("fir1=%d fir2=%d:\n",first1,first2);

    if(dep[u]>dep[v])
    {//puts("sdf");
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            node tmp=query(p[v],p[u],1,pos,1);
            swap(tmp.lsum,tmp.rsum);
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
 //   if(!first1&&!flag)tmp1.pf();
   // if(!first2&&!flag)tmp2.pf();
   // tmp.pf();
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
  //      printf("pos=%d %d %d %d %d\n",top[5],top[6],top[10],top[21],top[19]);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%d\n",temp.msum);
            }
    //        for(int i=1;i<=n;i++)printf("i=%d:%lld ",i,lca(i,i).sum);puts("");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 39468
final_rank: 8

code_snippet: #include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 2e5 + 10, inf = 0x3f3f3f3f, MOD = 1e9 + 7;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,-1,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==-1||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==-1)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    ll lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
    void pf()
    {
        printf("%lld %lld %lld %lld\n",lsum,rsum,msum,sum);
    }
}s[N<<2];
ll col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(max(a.msum,b.msum),a.sum+b.sum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
      //  printf("%d ",a[fp[l]]);
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int flag=1;
  //  if(u==9&&v==18)flag=0;
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2;
    while(f1!=f2)
    {
      // if(!flag)  printf("f1=%d f2=%d %d %d\n",f1,f2,u,v);
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
           // tmp.pf();
            v=fa[f2];f2=top[v];
          //  swap(f1,f2);
          //  swap(u,v);
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                node tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
           // tmp.pf();
            u=fa[f1];f1=top[u];
        }
        if(!first1&&!flag)tmp1.pf();
        if(!first2&&!flag)tmp2.pf();
    }
  //  printf("fir1=%d fir2=%d:\n",first1,first2);

    if(dep[u]>dep[v])
    {//puts("sdf");
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            node tmp=query(p[v],p[u],1,pos,1);
            swap(tmp.lsum,tmp.rsum);
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
 //   if(!first1&&!flag)tmp1.pf();
   // if(!first2&&!flag)tmp2.pf();
   // tmp.pf();
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
  //      printf("pos=%d %d %d %d %d\n",top[5],top[6],top[10],top[21],top[19]);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%lld\n",temp.msum);
            }
    //        for(int i=1;i<=n;i++)printf("i=%d:%lld ",i,lca(i,i).sum);puts("");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 51060
final_rank: 12

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,-1,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==-1||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==-1)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    ll lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
    void pf()
    {
        printf("%lld %lld %lld %lld\n",lsum,rsum,msum,sum);
    }
}s[N<<2];
ll col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(max(a.msum,b.msum),a.sum+b.sum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
      //  printf("%d ",a[fp[l]]);
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int flag=1;
  //  if(u==9&&v==18)flag=0;
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2;
    while(f1!=f2)
    {
      // if(!flag)  printf("f1=%d f2=%d %d %d\n",f1,f2,u,v);
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
           // tmp.pf();
            v=fa[f2];f2=top[v];
          //  swap(f1,f2);
          //  swap(u,v);
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                node tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
           // tmp.pf();
            u=fa[f1];f1=top[u];
        }
        if(!first1&&!flag)tmp1.pf();
        if(!first2&&!flag)tmp2.pf();
    }
  //  printf("fir1=%d fir2=%d:\n",first1,first2);

    if(dep[u]>dep[v])
    {//puts("sdf");
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            node tmp=query(p[v],p[u],1,pos,1);
            swap(tmp.lsum,tmp.rsum);
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
 //   if(!first1&&!flag)tmp1.pf();
   // if(!first2&&!flag)tmp2.pf();
   // tmp.pf();
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
  //      printf("pos=%d %d %d %d %d\n",top[5],top[6],top[10],top[21],top[19]);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);
            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%lld\n",temp.msum);
            }
    //        for(int i=1;i<=n;i++)printf("i=%d:%lld ",i,lca(i,i).sum);puts("");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 51252
final_rank: 13

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N = 200010;
const int inf = 0x3f3f3f3f;
struct edge
{
    int to,next;
    edge(){}
    edge(int to,int next):to(to),next(next){}
}e[N<<1];
int head[N],tot;
int top[N],a[N];
int fa[N],dep[N],num[N],p[N],fp[N],son[N],pos;
void init()
{
    memset(head,-1,sizeof head);
    tot=0;pos=0;
    memset(son,-1,sizeof son);
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)
{
    dep[u]=d;
    fa[u]=pre;num[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==-1||num[v]>num[son[u]])son[u]=v;
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=++pos;
    fp[p[u]]=u;
    if(son[u]==-1)return;
    getpos(son[u],sp);
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=fa[u])
        getpos(v,v);
    }
}
struct node
{
    ll lsum,rsum,msum,sum;
    void sp()
    {
        swap(lsum,rsum);
    }
    void pf()
    {
        printf("%lld %lld %lld %lld\n",lsum,rsum,msum,sum);
    }
}s[N<<2];
ll col[N<<2];
node calc(node a,node b)
{
    node c;
    c.sum=a.sum+b.sum;
    c.msum=max(max(a.msum,b.msum),a.sum+b.sum);
    c.lsum=max(a.lsum,a.sum+b.sum);
    c.rsum=max(b.rsum,a.sum+b.sum);
    c.lsum=max(c.lsum,a.sum+b.lsum);
    c.rsum=max(c.rsum,b.sum+a.rsum);
    c.msum=max(c.msum,max(c.lsum,c.rsum));
    c.msum=max(c.msum,a.rsum+b.lsum);
    return c;
}
void pushup(int rt)
{
    s[rt]=calc(s[rt<<1],s[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    col[rt]=inf;
    if(l==r)
    {
      //  printf("%d ",a[fp[l]]);
        s[rt].lsum=s[rt].rsum=s[rt].msum=s[rt].sum=a[fp[l]];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void pushdown(int rt,int len)
{
    if(col[rt]!=inf)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        s[rt<<1].sum=col[rt]*(len-(len>>1));
        s[rt<<1|1].sum=col[rt]*(len>>1);
        if(col[rt]>0)
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt]*(len-(len>>1));
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt]*(len>>1);
        }
        else
        {
            s[rt<<1].lsum=s[rt<<1].rsum=s[rt<<1].msum=col[rt];
            s[rt<<1|1].lsum=s[rt<<1|1].rsum=s[rt<<1|1].msum=col[rt];
        }
        col[rt]=inf;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]=c;
        s[rt].sum=col[rt]*(r-l+1);
        if(col[rt]>0)
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt]*(r-l+1);
        }
        else
        {
            s[rt].lsum=s[rt].rsum=s[rt].msum=col[rt];
        }
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
}
void change(int u,int v,int c)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
node query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)return s[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(R<=m)return query(L,R,lson);
    else if(L>m)return query(L,R,rson);
    else
    {
        node a=query(L,m,lson);
        node b=query(m+1,R,rson);
        return calc(a,b);
    }
}
node lca(int u,int v)
{
    int flag=1;
  //  if(u==9&&v==18)flag=0;
    int f1=top[u],f2=top[v],first1=1,first2=1;
    node tmp1,tmp2;
    while(f1!=f2)
    {
       if(!flag)  printf("f1=%d f2=%d %d %d\n",f1,f2,u,v);
        if(dep[f1]<dep[f2])
        {
            if(first2)
            {
                tmp2=query(p[f2],p[v],1,pos,1);
                first2=0;
            }
            else
            {
                tmp2=calc(query(p[f2],p[v],1,pos,1),tmp2);
            }
           // tmp.pf();
            v=fa[f2];f2=top[v];
          //  swap(f1,f2);
          //  swap(u,v);
        }
        else
        {
            if(first1)
            {
                tmp1=query(p[f1],p[u],1,pos,1);
                tmp1.sp();
                first1=0;
            }
            else
            {
                node tmp=query(p[f1],p[u],1,pos,1);
                tmp.sp();
                tmp1=calc(tmp1,tmp);
            }
           // tmp.pf();
            u=fa[f1];f1=top[u];
        }
        if(!first1&&!flag)tmp1.pf();
        if(!first2&&!flag)tmp2.pf();
    }
  //  printf("fir1=%d fir2=%d:\n",first1,first2);

    if(dep[u]>dep[v])
    {//puts("sdf");
        if(first1)
        {
            tmp1=query(p[v],p[u],1,pos,1);
            tmp1.sp();
            first1=0;
        }
        else
        {
            node tmp=query(p[v],p[u],1,pos,1);
            swap(tmp.lsum,tmp.rsum);
            tmp1=calc(tmp1,tmp);
        }
    }
    else
    {
        if(first2)
        {
            tmp2=query(p[u],p[v],1,pos,1);
            first2=0;
        }
        else tmp2=calc(query(p[u],p[v],1,pos,1),tmp2);
    }
    if(!first1&&!flag)tmp1.pf();
    if(!first2&&!flag)tmp2.pf();
   // tmp.pf();
    if(first1&&!first2)
    {
        return tmp2;
    }
    else if(!first1&&first2)return tmp1;
    else
    {
        return calc(tmp1,tmp2);
    }
}
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,pos,1);
  //      printf("pos=%d %d %d %d %d\n",top[5],top[6],top[10],top[21],top[19]);
        while(q--)
        {
            int op,a,b,c;
            scanf("%d%d%d%d",&op,&a,&b,&c);

            if(op==1)
            {
                change(a,b,c);
            }
            else
            {
                node temp=lca(a,b);
                printf("%lld\n",temp.msum);
            }
    //        for(int i=1;i<=n;i++)printf("i=%d:%lld ",i,lca(i,i).sum);puts("");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 51328
final_rank: 14

code_snippet: #include<cstdio>
#include<algorithm>
#define N 1200010
#define M 300000
#define INF 123456789
using namespace std;
int p[N],pre[N],tt[N],dp,deep[M],f[M],g[M];
int tot,id[M],value[M],e[M],jump[M];
int a,b,n,m,i;
long long ans,tmp,tmp1,tmp2,ls[N],rs[N],sum[N],s[N],l[N],r[N],v[N];
void link(int x,int y)
{
	dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
}
void dfs1(int x,int fa)
{
	int i,tmp1=0,tmp2=0;
	i=p[x];
	s[x]=1;
	while (i)
	{
		if (tt[i]!=fa)
		{
			deep[tt[i]]=deep[x]+1;
			f[tt[i]]=x;
			dfs1(tt[i],x);
			s[x]+=s[tt[i]];
			if (s[tt[i]]>tmp1)
			{
				tmp1=s[tt[i]];
				tmp2=tt[i];
			}
		}
		i=pre[i];
	}
	g[x]=tmp2;
}
void con(int x)
{
	int y=x;
	while (x)
	{
		tot++;
		id[x]=tot;
		jump[x]=y;
		x=g[x];
	}
}
void dfs2(int x,int fa)
{
	int i;
	if (id[x]==0)
		con(x);
	i=p[x];
	e[id[x]]=value[x];
	while (i)
	{
		if (tt[i]!=fa)
			dfs2(tt[i],x);
		i=pre[i];
	}
}
void updata(int x)
{
	ls[x]=max(ls[2*x],sum[2*x]+ls[2*x+1]);
	rs[x]=max(rs[2*x+1],sum[2*x+1]+rs[2*x]);
	s[x]=max(max(s[2*x],s[2*x+1]),rs[2*x]+ls[2*x+1]);
	sum[x]=sum[2*x]+sum[2*x+1];
}
void build(int x,int a,int b)
{
	int m;
	l[x]=a;r[x]=b;v[x]=INF;
	if (b-a>1)
	{
		m=(l[x]+r[x])>>1;
		build(2*x,a,m);
		build(2*x+1,m,b);
		updata(x);
	}
	else
	{
		ls[x]=e[b];
		rs[x]=e[b];
		s[x]=e[b];
		sum[x]=e[b];
	}
}
void clean(int x)
{
	if (v[x]!=INF)
	{
		sum[x]=(r[x]-l[x])*v[x];
		if (v[x]>0)
			s[x]=sum[x];
		else
			s[x]=v[x];
		ls[x]=s[x];
		rs[x]=s[x];
		v[2*x]=v[x];
		v[2*x+1]=v[x];
		v[x]=INF;
	}
}
void change(int x,int a,int b,int c)
{
	int m;
	clean(x);
	if ((a<=l[x])&&(r[x]<=b))
	{
		v[x]=c;
		return;
	}
	m=(l[x]+r[x])>>1;
	if (a<m) change(2*x,a,b,c);
	if (m<b) change(2*x+1,a,b,c);
	clean(2*x);clean(2*x+1);
	updata(x);
}
void query(int x,int a,int b)
{
	int m;
	clean(x);
	if ((a<=l[x])&&(r[x]<=b))
	{
		ans=max(ans,max(s[x],tmp+rs[x]));
		tmp=max(tmp+sum[x],ls[x]);
		return;
	}
	m=(l[x]+r[x])>>1;
	if (m<b) query(2*x+1,a,b);
	if (a<m) query(2*x,a,b);
}
void Q(int a,int b,int c,int typ)
{
	int t;
	while (1)
	{
		if (jump[a]==jump[b])
		{
			if (deep[a]<deep[b])
			{
				if (typ==1)
					change(1,id[a]-1,id[b],c);
				else
				{
					tmp=tmp2;
					query(1,id[a]-1,id[b]);
					tmp2=tmp;
				}
			}
			else
			{
				if (typ==1)
					change(1,id[b]-1,id[a],c);
				else
				{
					tmp=tmp1;
					query(1,id[b]-1,id[a]);
					tmp1=tmp;
				}
			}
			return;
		}
		if (deep[jump[a]]<deep[jump[b]])
		{
			if (typ==1)
				change(1,id[jump[b]]-1,id[b],c);
			else
			{
				tmp=tmp2;
				query(1,id[jump[b]]-1,id[b]);
				tmp2=tmp;
			}
			b=f[jump[b]];
		}
		else
		{
			if (typ==1)
				change(1,id[jump[a]]-1,id[a],c);
			else
			{
				tmp=tmp1;
				query(1,id[jump[a]]-1,id[a]);
				tmp1=tmp;
			}
			a=f[jump[a]];
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)
		scanf("%d",&value[i]);
	for (i=1;i<n;i++)
	{
		scanf("%d%d",&a,&b);
		link(a,b);
		link(b,a);
	}
	dfs1(1,0);
	dfs2(1,0);
	build(1,0,n);


	for (i=1;i<=m;i++)
	{
		int typ,c;
		scanf("%d%d%d%d",&typ,&a,&b,&c);
		if (typ==1)
			Q(a,b,c,1);
		else
		{
			ans=-0x37373737;
			ans=ans*10000;
			tmp1=0;tmp2=0;
			Q(a,b,c,2);
			ans=max(ans,tmp1+tmp2);
			printf("%lld\n",ans);
		}
	}

}
accuracy: 1
time_ms: 310
memory_kb: 78944
final_rank: 17

code_snippet: #include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>

#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)

using std::min;
using std::max;
using std::pair;
using std::make_pair;
typedef pair<int, int> Pair;

const int N = 200000 + 10;

std::vector<int> neighbors[N];
int weight[N], n, m;

const int S = N << 2;
const int INF = 1 << 30;

#define L(u) ((u) << 1)
#define R(u) ((u) << 1 | 1)

int depth[N], pos[N], top[N], size[N], father[N], son[N], son_weight[N], temp_value[N];
int value[S], length[S], sum[S], leftmost[S], rightmost[S], flag[S];
int counter;

void dfs_1(int u, int p) {
	depth[u] = p == 0 ? 0 : depth[p] + 1;
	father[u] = p;
	size[u] = 1;
	int& pivot = son[u];
	foreach(iter, neighbors[u]) {
		int v = *iter;
		if (v != p) {
			dfs_1(v, u);
			size[u] += size[v];
			if (pivot == 0 || size[v] > size[pivot]) {
				pivot = v;
				son_weight[u] = weight[pivot];
			}
		}
	}
}

void dfs_2(int u, int t) {
	pos[u] = ++ counter;
	top[u] = t;
	temp_value[counter] = weight[u];
	if (son[u]) {
		dfs_2(son[u], t);
	}
	foreach(iter, neighbors[u]) {
		int v = *iter;
		if (v != father[u] && v != son[u]) {
			dfs_2(v, v);
		}
	}
}

void update(int u) {
	sum[u] = sum[L(u)] + sum[R(u)];
	leftmost[u] = max(leftmost[L(u)], sum[L(u)] + leftmost[R(u)]);
	rightmost[u] = max(rightmost[R(u)], sum[R(u)] + rightmost[L(u)]);
	value[u] = max(value[L(u)], value[R(u)]);
	value[u] = max(value[u], rightmost[L(u)] + leftmost[R(u)]);
}

void build(int u, int l, int r) {
	length[u] = r - l + 1;
	flag[u] = INF;
	if (l == r) {
		value[u] = sum[u] = temp_value[l];
		leftmost[u] = rightmost[u] = sum[u];
	} else {
		int m = l + r >> 1;
		build(L(u), l, m);
		build(R(u), m + 1, r);
		update(u);
	}
}

void push_down(int u) {
	if (flag[u] != INF) {
		for (int i = 0; i < 2; ++ i) {
			int v = u << 1 | i;
			flag[v] = flag[u];
			sum[v] = flag[v] * length[v];
			value[v] = leftmost[v] = rightmost[v] = flag[v] >= 0 ? sum[v] : flag[v];
		}	
	}
	flag[u] = INF;
}

void insert(int u, int l, int r, int a, int b, int v) {
	if (a > r || b < l) {
		return;
	}
	if (a <= l && b >= r) {
		flag[u] = v;
		sum[u] = v * length[u];
		leftmost[u] = rightmost[u] = value[u] = sum[u] > 0 ? sum[u] : v;
	} else {
		push_down(u);
		int m = l + r >> 1;
		insert(L(u), l, m, a, b, v);
		insert(R(u), m + 1, r, a, b, v);
		update(u);
	}
}

struct Data {
	int sum, leftmost, rightmost, value;
	Data(int sum = 0, int leftmost = -INF, int rightmost = -INF, int value = -INF):
		sum(sum), leftmost(leftmost), value(value), rightmost(rightmost) {
	}
};

inline void update_max(int& a, int b) {
	if (a < b) {
		a = b;
	}
}

void get_data(int u, int l, int r, int a, int b, Data& data) {
	if (a > r || b < l) {
		return;
	}
	if (a <= l && b >= r) {
		data = Data(sum[u], leftmost[u], rightmost[u], value[u]);
	} else {
		push_down(u);
		int m = l + r >> 1;
		Data left_data, right_data;
		get_data(L(u), l, m, a, b, left_data);
		get_data(R(u), m + 1, r, a, b, right_data);
		data.leftmost = max(left_data.leftmost, left_data.sum + right_data.leftmost);
		data.rightmost = max(right_data.rightmost, right_data.sum + left_data.rightmost);
		data.value = max(max(left_data.value, right_data.value), left_data.rightmost + right_data.leftmost);
		data.sum = left_data.sum + right_data.sum;
	}
}

void link_cut() {
	dfs_1(1, 0);
	counter = 0, dfs_2(1, 1);
	build(1, 1, n);
}

struct Triple {
	int a, b, c;
	Triple(int a = 0, int b = 0, int c = 0):
		a(a), b(b), c(c) {
	}
};

std::vector<Triple> blocks, right;
void get_blocks(int u, int v) {
	blocks.clear();
	right.clear();
	for (int du = top[u], dv = top[v]; du != dv; ) {
		if (depth[du] >= depth[dv]) {
			blocks.push_back(Triple(u, du, 0));
			u = father[du];
			du = top[u];
		} else {
			right.push_back(Triple(v, dv, 1));
			v = father[dv];
			dv = top[v];
		}
	}
	if (depth[u] < depth[v]) {
		blocks.push_back(Triple(v, u, 1));
	} else {
		blocks.push_back(Triple(u, v, 0));
	}
	for (int i = right.size() - 1; i >= 0; -- i) {
		blocks.push_back(right[i]);
	}
}

void cover(int u, int v, int c) {
	get_blocks(u, v);
	foreach(iter, blocks) {
		int u = (*iter).a;
		int v = (*iter).b;
		insert(1, 1, n, pos[v], pos[u], c);
	}
}

int query(int u, int v) {
	get_blocks(u, v);
	int answer = -INF, now = 0;
	foreach(iter, blocks) {
		int u = (*iter).a;
		int v = (*iter).b;
		Data data;
		get_data(1, 1, n, pos[v], pos[u], data);
		int left = data.rightmost;
		int right = data.leftmost;
		if ((*iter).c == 1) {
			std::swap(left, right);
		}
		
		answer = max(answer, data.value);
		answer = max(answer, now + left);
		now = max(max(0, now + data.sum), right);
	}
	return answer;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d", weight + i);
	}
	for (int i = 1; i < n; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		neighbors[u].push_back(v);
		neighbors[v].push_back(u);
	}
	link_cut();
	while (m --) {
		int command, a, b, c;
		scanf("%d%d%d%d", &command, &a, &b, &c);
		if (command == 1) {
			cover(a, b, c);
		} else {
			printf("%d\n", query(a, b));
		}
	}
	return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 52776
final_rank: 15