結果

問題 No.399 動的な領主
ユーザー ferinferin
提出日時 2020-01-02 22:45:43
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 681 ms / 2,000 ms
コード長 6,340 bytes
コンパイル時間 2,243 ms
コンパイル使用メモリ 182,540 KB
実行使用メモリ 12,644 KB
最終ジャッジ日時 2023-08-14 18:42:17
合計ジャッジ時間 8,153 ms
ジャッジサーバーID
(参考情報)
judge15 / judge12
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,380 KB
testcase_01 AC 1 ms
4,380 KB
testcase_02 AC 2 ms
4,384 KB
testcase_03 AC 2 ms
4,376 KB
testcase_04 AC 3 ms
4,376 KB
testcase_05 AC 28 ms
4,380 KB
testcase_06 AC 435 ms
12,428 KB
testcase_07 AC 443 ms
12,628 KB
testcase_08 AC 424 ms
12,436 KB
testcase_09 AC 416 ms
12,596 KB
testcase_10 AC 4 ms
4,380 KB
testcase_11 AC 18 ms
4,376 KB
testcase_12 AC 241 ms
12,412 KB
testcase_13 AC 227 ms
12,412 KB
testcase_14 AC 55 ms
12,552 KB
testcase_15 AC 216 ms
12,644 KB
testcase_16 AC 243 ms
12,456 KB
testcase_17 AC 681 ms
12,508 KB
testcase_18 AC 485 ms
12,508 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
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> void chmin(T &a, const T &b) { a = min(a, b); }
template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }
struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;
#ifdef DEBUG_ 
#include "../program_contest_library/memo/dump.hpp"
#else
#define dump(...)
#endif
const ll INF = 1LL<<60;

template<typename M>
class LinkCutTree {
public:
    using T = typename M::T;
    using E = typename M::E;

    struct node {
        int sz;
        T val, sum;
        E lazy;
        node *left, *right, *par;
        bool rev;
        node() : sz(1), val(M::T0()), sum(M::T0()), lazy(M::E0()),
            left(nullptr), right(nullptr), par(nullptr), rev(false) {}
        node(T _val) : sz(1), val(_val), sum(_val), lazy(M::E0()),
            left(nullptr), right(nullptr), par(nullptr), rev(false) {}
        inline bool isRoot() const {
            return (!par) || (par->left != this && par->right != this);
        }
        void push() {
            if(lazy != M::E0()) {
                val = M::g(val, lazy, 1), sum = M::g(sum, lazy, sz);
                if(left) left->lazy = M::h(left->lazy, lazy);
                if(right) right->lazy = M::h(right->lazy, lazy);
                lazy = M::E0();
            }
            if(rev) {
                swap(left, right);
                sum = M::s(sum);
                if(left) left->rev ^= true;
                if(right) right->rev ^= true;
                rev = false;
            }
        }
        void eval() {
            sz = 1, sum = val;
            if(left) left->push(), sz += left->sz, sum = M::f(left->sum, sum);
            if(right) right->push(), sz += right->sz, sum = M::f(sum, right->sum);
        }
    };
 
private:
    void rotate(node* u, bool right) {
        node *p = u->par, *g = p->par;
        if(right) {
            if((p->left = u->right)) u->right->par = p;
            u->right = p, p->par = u;
        } else {
            if((p->right = u->left)) u->left->par = p;
            u->left = p, p->par = u;
        }
        p->eval(), u->eval(), u->par = g;
        if(!g) return;
        if(g->left == p) g->left = u;
        if(g->right == p) g->right = u;
        g->eval();
    }
    // uをsplay木の根にする
    void splay(node* u) {
        while(!u->isRoot()) {
            node *p = u->par, *gp = p->par;
            if(p->isRoot()) { // zig
                p->push(), u->push();
                rotate(u, (u == p->left));
            } else {
                gp->push(), p->push(), u->push();
                bool flag = (u == p->left);
                if((u == p->left) == (p == gp->left)) { // zig-zig
                    rotate(p, flag), rotate(u, flag);
                } else { // zig-zag
                    rotate(u, flag), rotate(u, !flag);
                }
            }
        }
        u->push();
    }
    // 頂点uから根へのパスをつなげる
    node* expose(node* u) {
        node* last = nullptr;
        for(node* v = u; v; v = v->par) {
            splay(v);
            v->right = last;
            v->eval();
            last = v;
        }
        splay(u);
        return last;
    }
    void evert(node* u) {
        expose(u), u->rev = !(u->rev), u->push();
    }
    bool connected(node *u, node *v) {
        expose(u), expose(v);
        return u == v || u->par;
    }
    void link(node *u, node *v) {
        evert(u), u->par = v;
    }
    void cut(node* u) { // uと親の辺を切る
        expose(u), u->left->par = nullptr, u->left = nullptr, u->eval();
    }
    void cut(node* u, node* v) {
        expose(u), expose(v);
        if(u->isRoot()) u->par = nullptr;
        else v->left->par = nullptr, v->left = nullptr, v->eval();
    }
    node* lca(node* u, node* v) {
        expose(u);
        return expose(v);
    }
    int depth(node* u) {
        expose(u);
        return u->sz - 1;
    }
    void toRoot_range(node* u, const E x) {
        expose(u);
        u->lazy = M::h(u->lazy, x), u->push();
    }
    void range(node* u, node* v, const E x) {
        evert(u), expose(v);
        v->lazy = M::h(v->lazy, x), v->push();
    }
    void toRoot_query(node* u) {
        expose(u);
        return u->sum;
    }
    T query(node* u, node* v) {
        evert(u), expose(v);
        return v->sum;
    }
 
public:
    const int n;
    node** arr;
    LinkCutTree(const vector<T> &v) : n(v.size()) { 
        arr = new node*[n];
        REP(i, n) arr[i] = new node(v[i]);
    }
    // ~LinkCutTree(){
    //     REP(i, n) delete arr[i];
    //     delete[] arr;
    // }
    bool connected(int id1, int id2){ return connected(arr[id1], arr[id2]); }
    void link(int id1, int id2){ return link(arr[id1], arr[id2]); }
    void cut(int id){ return cut(arr[id]); } // uと親の辺を切る
    void cut(int id1, int id2){ return cut(arr[id1], arr[id2]); }
    int lca(int id1, int id2){ return static_cast<size_t>(lca(arr[id1], arr[id2]) - arr[0]); }
    void evert(int id){ return evert(arr[id]); }
    int depth(int id){ return depth(arr[id]); }
    void toRoot_range(int id, const E x){ return toRoot_range(arr[id], x); }
    void range(int id1, int id2, const E x){ return range(arr[id1], arr[id2], x); }
    T toRoot_query(int id){ return toRoot_query(arr[id]); }
    T query(int id1, int id2){ return query(arr[id1], arr[id2]); }
};

struct sum_monoid {
    using T = ll;
    using E = ll;
    static T T0() { return 0; }
    static constexpr E E0() { return 0; }
    static T f(const T &x, const T &y) { return x+y; }
    static T g(const T &x, const E &y, int sz) { return x + y*sz; }
    static E h(const E &x, const E &y) { return x+y; }
    static T s(const T &x) { return x; }
};

int main(void) {
    ll n;
    cin >> n;
    vector<ll> init(n, 1);
    LinkCutTree<sum_monoid> lct(init);
    REP(i, n-1) {
        ll u, v;
        cin >> u >> v;
        u--, v--;
        lct.link(u, v);
    }

    ll q, ret = 0;
    cin >> q;
    while(q--) {
        ll u, v;
        cin >> u >> v;
        u--, v--;
        ret += lct.query(u, v);
        lct.range(u, v, 1);
    }
    cout << ret << endl;

    return 0;
}
0