結果

問題 No.900 aδδitivee
ユーザー ferinferin
提出日時 2019-10-04 22:16:40
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 345 ms / 2,000 ms
コード長 9,391 bytes
コンパイル時間 2,238 ms
コンパイル使用メモリ 197,308 KB
実行使用メモリ 34,956 KB
最終ジャッジ日時 2024-10-03 07:55:14
合計ジャッジ時間 10,785 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,820 KB
testcase_01 AC 2 ms
6,816 KB
testcase_02 AC 2 ms
6,816 KB
testcase_03 AC 2 ms
6,820 KB
testcase_04 AC 2 ms
6,816 KB
testcase_05 AC 3 ms
6,820 KB
testcase_06 AC 2 ms
6,820 KB
testcase_07 AC 337 ms
34,916 KB
testcase_08 AC 338 ms
34,824 KB
testcase_09 AC 332 ms
34,956 KB
testcase_10 AC 331 ms
34,784 KB
testcase_11 AC 342 ms
34,812 KB
testcase_12 AC 345 ms
34,752 KB
testcase_13 AC 344 ms
34,808 KB
testcase_14 AC 341 ms
34,848 KB
testcase_15 AC 326 ms
34,752 KB
testcase_16 AC 323 ms
34,816 KB
testcase_17 AC 327 ms
34,772 KB
testcase_18 AC 325 ms
34,944 KB
testcase_19 AC 329 ms
34,928 KB
testcase_20 AC 326 ms
34,780 KB
testcase_21 AC 339 ms
34,744 KB
testcase_22 AC 254 ms
34,768 KB
testcase_23 AC 256 ms
34,776 KB
testcase_24 AC 267 ms
34,896 KB
testcase_25 AC 254 ms
34,768 KB
testcase_26 AC 257 ms
34,704 KB
testcase_27 AC 267 ms
34,740 KB
testcase_28 AC 255 ms
34,788 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>

using namespace std;
using ll = long long;
// #define int ll
using PII = pair<ll, ll>;

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

template<typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template<typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }
template<typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; }
template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); }

template<typename T> vector<T> make_v(size_t a) { return vector<T>(a); }
template<typename T,typename... Ts>
auto make_v(size_t a,Ts... ts) { 
    return vector<decltype(make_v<T>(ts...))>(a,make_v<T>(ts...));
}
template<typename T,typename V> typename enable_if<is_class<T>::value==0>::type
fill_v(T &t, const V &v) { t=v; }
template<typename T,typename V> typename enable_if<is_class<T>::value!=0>::type
fill_v(T &t, const V &v ) { for(auto &e:t) fill_v(e,v); }

template<class S,class T>
ostream &operator <<(ostream& out,const pair<S,T>& a){
    out<<'('<<a.first<<','<<a.second<<')'; return out;
}
template<class T>
ostream &operator <<(ostream& out,const vector<T>& a){
    out<<'['; for(T i: a) {out<<i<<',';} out<<']'; return out;
}

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; // DRUL
const int INF = 1<<30;
const ll LLINF = 1LL<<60;
const ll MOD = 1000000007;


struct HLDecomposition {
    int n, pos;
    vector<vector<ll>> g;
    vector<ll> vid,   // HL分解後のグラフでのid
        head,  // 頂点が属するheavy-pathのheadのid
        sub,   // 部分木のサイズ
        hvy,   // heavy-path上での次の頂点のid
        par,   // 親のid
        depth, // 深さ
        inv,   // HL分解前のグラフのid(添え字が分解後のid)
        type,  // 森をHL分解するときの属する木の番号
        ps,    // 行きがけ順
        pt;    // 帰りがけ順

    // 根rtからdfsして部分木の大きさ、heavy-edgeの判定などをする
    void dfs1(ll rt) {
        stack<PII> st;
        par[rt] = -1;
        depth[rt] = 0;
        st.emplace(rt, 0);
        while(st.size()) {
            ll v = st.top().first;
            ll &i = st.top().second;
            if(i < (ll)g[v].size()) {
                ll u = g[v][i++];
                if(u == par[v]) continue;
                par[u] = v;
                depth[u] = depth[v]+1;
                st.emplace(u, 0);
            } else {
                st.pop();
                for(ll &u: g[v]){
                    if(u == par[v]) swap(u, g[v].back());
                    if(u == par[v]) continue;
                    sub[v] += sub[u];
                    if(sub[u]>sub[g[v].front()]) swap(u, g[v].front());
                }
            }
        }
    }
    // 根r、c番目の木についてchainについての情報をまとめる
    void dfs2(ll r, ll c) {
        using T = tuple<ll, ll, ll>;
        stack<T> st;
        st.emplace(r,r,0);
        while(!st.empty()) {
            ll v,h;
            tie(v,h,ignore)=st.top();
            ll &i=get<2>(st.top());
            if(!i) {
                type[v]=c;
                ps[v]=vid[v]=pos++;
                inv[vid[v]]=v;
                head[v]=h;
                hvy[v]=(g[v].empty()?-1:g[v][0]);
                if(hvy[v]==par[v]) hvy[v]=-1;
            }
            if(i<(ll)g[v].size()) {
                ll u=g[v][i++];
                if(u==par[v]) continue;
                st.emplace(u,(hvy[v]==u?h:u),0);
            } else {
                st.pop();
                pt[v]=pos;
            }
        }
    }

    HLDecomposition(){}
    HLDecomposition(ll sz):
        n(sz), pos(0), g(n),
        vid(n,-1), head(n), sub(n,1), hvy(n,-1),
        par(n), depth(n), inv(n), type(n), ps(n), pt(n) {}

    void add_edge(ll u, ll v) {
        g[u].push_back(v);
        g[v].push_back(u);
    }
    void build(vector<ll> rs=vector<ll>(1,0)) {
        ll c=0;
        for(ll r: rs) {
            dfs1(r);
            dfs2(r, c++);
        }
    }

    // 頂点に対する処理 [u,v] 開区間なので注意!!!
    void for_each(ll u, ll v, const function<void(ll,ll)>& f) {
        while(1){
            if(vid[u]>vid[v]) swap(u,v);
            // [max(vid[head[v]],vid[u]), vid[v]] の区間についての操作を行う
            f(max(vid[head[v]], vid[u]), vid[v]);
            if(head[u]!=head[v]) v = par[head[v]];
            else break;
        }
    }
    // 辺に対する処理 [u,v] 開区間なので注意!!!
    void for_each_edge(ll u, ll v, const function<void(ll,ll)>& f) {
        while(1) {
            if(vid[u]>vid[v]) swap(u,v);
            if(head[u]!=head[v]) {
                f(vid[head[v]], vid[v]);
                v = par[head[v]];
            } else {
                if(u!=v) f(vid[u]+1, vid[v]);
                break;
            }
        }
    }
    ll lca(ll u, ll v) {
        while(1) {
            if(vid[u]>vid[v]) swap(u,v);
            if(head[u]==head[v]) return u;
            v = par[head[v]];
        }
    }
    ll distance(ll u, ll v) {
        return depth[u] + depth[v] - 2*depth[lca(u,v)];
    }
};
/*
パスu-vの頂点属性クエリ → hld.for_each(u, v, f)
パスu-vの辺属性クエリ → hld.for_each_edge(u, v, f)
頂点vの部分木に対するクエリ → 区間[hld.vid[u]+1, hld.vid[u] + hld.sub[u]) に操作
*/


template <typename Monoid>
struct lazysegtree {
    using T = typename Monoid::T;
    using E = typename Monoid::E;
    int n, height;
    vector<T> dat;
    vector<E> lazy;

    lazysegtree() {}
    lazysegtree(int n_) {
        n = 1, height = 0;
        while(n < n_) { n *= 2; height++; }
        dat.assign(n*2, Monoid::dt());
        lazy.assign(n*2, Monoid::de());
    }
    void build(vector<T> v) {
        REP(i, v.size()) dat[i+n] = v[i];
        for(int i=n-1; i>0; --i) dat[i] = Monoid::f(dat[i*2], dat[i*2+1]);
    }

    inline T reflect(int k) { return lazy[k]==Monoid::de()?dat[k]:Monoid::g(dat[k], lazy[k]); }
    inline void eval(int k) {
        if(lazy[k] == Monoid::de()) return;
        lazy[2*k]   = Monoid::h(lazy[k*2],   lazy[k]);
        lazy[2*k+1] = Monoid::h(lazy[k*2+1], lazy[k]);
        dat[k] = reflect(k);
        lazy[k] = Monoid::de();
    }
    inline void thrust(int k) { for(int i=height;i;--i) eval(k>>i); }
    inline void recalc(int k) { while(k>>=1) dat[k] = Monoid::f(reflect(k*2), reflect(k*2+1)); }

    void update(int a, int b, E x) {
        thrust(a+=n);
        thrust(b+=n-1);
        for(int l=a, r=b+1; l<r; l>>=1,r>>=1) {
            if(l&1) lazy[l] = Monoid::h(lazy[l], x), ++l;
            if(r&1) --r, lazy[r] = Monoid::h(lazy[r], x);
        }
        recalc(a);
        recalc(b);
    }
    T query(int a, int b) {
        thrust(a+=n);
        thrust(b+=n-1);
        T vl=Monoid::dt(), vr=Monoid::dt();
        for(int l=a, r=b+1; l<r; l>>=1,r>>=1) {
            if(l&1) vl=Monoid::f(vl, reflect(l++));
            if(r&1) vr=Monoid::f(reflect(--r), vr);
        }
        return Monoid::f(vl, vr);
    }

    friend ostream &operator <<(ostream& out,const lazysegtree<Monoid>& seg) {
        out << "---------------------" << endl;
        int cnt = 1;
        for(int i=1; i<=seg.n; i*=2) {
            REP(j, i) {
                out << "(" << seg.dat[cnt] << "," << seg.lazy[cnt] << ") ";
                cnt++;
            }
            out << endl;
        }
        out << "---------------------" << endl;
        return out;
    }
};

struct node {
    ll sum, max, min, len;
    node() : sum(0), max(-LLINF), min(LLINF), len(0) {}
    node(ll a, ll b, ll c, ll d) : sum(a), max(b), min(c), len(d) {}
};
struct linear_exp {
    using T = node;
    using E = PII;
    static T dt() { return node(); }
    static constexpr E de() { return PII(1, 0); }
    static T f(const T &a, const T &b) {
        node ret;
        ret.sum = a.sum + b.sum;
        ret.min = min(a.min, b.min);
        ret.max = max(a.max, b.max);
        ret.len = a.len + b.len;
        return ret;
    }
    static T g(const T &a, const E &b) {
        node ret;
        ret.sum = b.first*a.sum+b.second*a.len;
        ret.min = b.first*a.min+b.second;
        ret.max = b.first*a.max+b.second;
        ret.len = a.len;
        return ret;
    }
    static E h(const E &a, const E &b) {
        return PII(b.first*a.first, b.first*a.second+b.second);
    }
};

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

    ll n;
    cin >> n;
    HLDecomposition hld(n);
    vector<ll> a(n), b(n), c(n);
    REP(i, n-1) {
        cin >> a[i] >> b[i] >> c[i];
        hld.add_edge(a[i], b[i]);
    }    
    hld.build();

    lazysegtree<linear_exp> seg(n);
    seg.build(vector<node>(n, node(0, 0, 0, 1)));
    REP(i, n-1) {
        hld.for_each_edge(a[i], b[i], [&](ll u, ll v){
            seg.update(u, v+1, PII(1, c[i]));
        });
    }

    ll q;
    cin >> q;
    while(q--) {
        ll type;
        cin >> type;
        if(type == 1) {
            ll u, x;
            cin >> u >> x;
            seg.update(hld.vid[u]+1, hld.vid[u] + hld.sub[u], PII(1, x));
        } else {
            ll u;
            cin >> u;
            ll ans = 0;
            hld.for_each_edge(0, u, [&](ll p, ll q){
                ans += seg.query(p, q+1).sum;
            });
            cout << ans << endl;
        }
    }

    return 0;
}
0