結果

問題 No.399 動的な領主
ユーザー xuzijian629xuzijian629
提出日時 2019-10-28 15:03:06
言語 C++17
(gcc 13.2.0 + boost 1.83.0)
結果
AC  
実行時間 893 ms / 2,000 ms
コード長 11,256 bytes
コンパイル時間 2,797 ms
コンパイル使用メモリ 217,980 KB
実行使用メモリ 10,236 KB
最終ジャッジ日時 2023-10-12 23:04:53
合計ジャッジ時間 12,921 ms
ジャッジサーバーID
(参考情報)
judge15 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,356 KB
testcase_01 AC 1 ms
4,356 KB
testcase_02 AC 2 ms
4,348 KB
testcase_03 AC 2 ms
4,352 KB
testcase_04 AC 6 ms
4,352 KB
testcase_05 AC 64 ms
4,352 KB
testcase_06 AC 866 ms
10,136 KB
testcase_07 AC 893 ms
10,144 KB
testcase_08 AC 851 ms
10,224 KB
testcase_09 AC 831 ms
10,228 KB
testcase_10 AC 7 ms
4,348 KB
testcase_11 AC 40 ms
4,352 KB
testcase_12 AC 524 ms
10,200 KB
testcase_13 AC 488 ms
10,092 KB
testcase_14 AC 505 ms
10,092 KB
testcase_15 AC 764 ms
10,148 KB
testcase_16 AC 790 ms
10,172 KB
testcase_17 AC 832 ms
10,100 KB
testcase_18 AC 852 ms
10,236 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

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

// T0: 元の配列のモノイド
// T1: T0に対する作用素モノイド
template <class T0, class T1>
class BaseLinkCutTree {
    // T0上の演算、単位元
    virtual T0 f0(T0, T0) = 0;
    const T0 u0;
    // T1上の演算、単位元
    virtual T1 f1(T1, T1) = 0;
    const T1 u1;
    // T0に対するT1の作用
    virtual T0 g(T0, T1) = 0;
    // 多数のt1(T1)に対するf1の合成
    virtual T1 p(T1, int) = 0;

    struct Node {
        int idx, cnt;
        T0 val, acc;
        T1 lazy;
        Node *left, *right, *par;
        Node(int idx, T0 val, T0 u0, T1 u1)
            : idx(idx), cnt(1), val(val), lazy(u1), acc(u0), left(nullptr), right(nullptr), par(nullptr) {}
        bool is_root() { return (!par) || (par->left != this && par->right != this); }
    };

    void push(Node* t) {
        if (t->cnt < 0) {
            swap(t->left, t->right);
            if (t->left) t->left->cnt = -(t->left->cnt);
            if (t->right) t->right->cnt = -(t->right->cnt);
            t->cnt = -t->cnt;
        }
        if (t->lazy != u1) {
            t->val = g(t->val, p(t->lazy, 1));
            t->acc = g(t->acc, p(t->lazy, t->cnt));
            if (t->left) t->left->lazy = g(t->left->lazy, p(t->lazy, 1));
            if (t->right) t->right->lazy = g(t->right->lazy, p(t->lazy, 1));
            t->lazy = u1;
        }
    }

    void eval(Node* t) {
        bool flag = (t->cnt < 0);
        t->cnt = 1, t->acc = t->val;
        if (t->left) push(t->left), t->cnt += _abs(t->left->cnt), t->acc = f1(t->left->acc, t->acc);
        if (t->right) push(t->right), t->cnt += _abs(t->right->cnt), t->acc = f1(t->acc, t->right->acc);
        if (flag) t->cnt = -t->cnt;
    }

    vector<Node*> nodes;

    inline static int _abs(int val) { return val & 0x7fffffff; }
    // 回転
    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;
        }
        eval(p), eval(u), u->par = g;
        if (!g) return;
        if (g->left == p) g->left = u;
        if (g->right == p) g->right = u;
        eval(g);
    }
    // uをsplay木の根にする
    void splay(Node* u) {
        while (!(u->is_root())) {
            Node *p = u->par, *gp = p->par;
            if (p->is_root()) {  // zig
                push(p), push(u);
                rotate(u, (u == p->left));
            } else {
                push(gp), push(p), push(u);
                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);
                }
            }
        }
        push(u);
    }
    Node* expose(Node* u) {
        Node* last = nullptr;
        for (Node* v = u; v; v = v->par) {
            splay(v);
            v->right = last;
            eval(v);
            last = v;
        }
        splay(u);
        return last;
    }
    bool connected(Node* u, Node* v) {
        expose(u), expose(v);
        return u->par;
    }
    // u(child)とv(parent)を結ぶ
    void link(Node* u, Node* v) {
        assert(!connected(u, v));
        evert(u), u->par = v;
    }
    // uと親を切り離す
    void cut(Node* u) {
        expose(u);
        assert(u->left);
        u->left->par = nullptr, u->left = nullptr, eval(u);
    }
    Node* lca(Node* u, Node* v) {
        // assert(connected(u, v));
        expose(u);
        return expose(v);
    }
    Node* get_kth(Node* v, int k) {
        expose(v);
        while (v) {
            eval(v);
            if (v->right && v->right->cnt > k) {
                v = v->right;
            } else {
                if (v->right) k -= v->right->cnt;
                if (k == 0) return v;
                k--;
                v = v->left;
            }
        }
        return nullptr;
    }
    Node* get_root(Node* v) {
        expose(v);
        while (v->left) {
            eval(v);
            v = v->left;
        }
        return v;
    }
    void evert(Node* u) { expose(u), u->cnt = -(u->cnt); }
    int depth(Node* u) {
        expose(u);
        return _abs(u->cnt) - 1;
    }
    void update(Node* u, Node* v, const T1 x) {
        evert(u), expose(v);
        v->lazy = f1(v->lazy, x), push(v);
    }
    T0 query(Node* u, Node* v) {
        evert(u), expose(v);
        return v->acc;
    }

public:
    BaseLinkCutTree(T0 u0, T1 u1) : u0(u0), u1(u1) {}
    int make_new_node(T0 v) {
        int idx = nodes.size();
        nodes.push_back(new Node(idx, v, u0, u1));
        return idx;
    }
    bool connected(int a, int b) { return connected(nodes[a], nodes[b]); }
    // uとvをつなぐ(evertせずに使える)
    void link(int u, int v) { return link(nodes[u], nodes[v]); }
    // vを親と切り離す
    void cut(int v) { return cut(nodes[v]); }
    int lca(int u, int v) { return lca(nodes[u], nodes[v])->idx; }
    // vから根にk個たどった頂点を返す。とくにget_kth(v, 0)はv
    int get_kth(int v, int k) { return get_kth(nodes[v], k)->idx; }
    int get_root(int v) { return get_root(nodes[v])->idx; }
    // vを根にもってくる
    void evert(int v) { return evert(nodes[v]); }
    int depth(int v) { return depth(nodes[v]); }
    // uvパスに現れるすべての頂点にxを作用させる
    void update(int u, int v, T1 x) { return update(nodes[u], nodes[v], x); }
    void update(int v, T1 x) { update(v, v, x); }
    // uvパスに現れるすべての頂点の累積を求める
    T0 query(int u, int v) { return query(nodes[u], nodes[v]); }
    T0 query(int v) { return query(v, v); }
};

template <class T0, class T1>
struct MinUpdateQuery : public BaseLinkCutTree<T0, T1> {
    using BaseLinkCutTree<T0, T1>::BaseLinkCutTree;
    MinUpdateQuery() : MinUpdateQuery(numeric_limits<T0>::max(), numeric_limits<T1>::min()) {}
    T0 f0(T0 x, T0 y) override { return min(x, y); }
    T1 f1(T1 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T0 g(T0 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T1 p(T1 x, int len) override { return x; }
};

template <class T0, class T1>
struct SumAddQuery : public BaseLinkCutTree<T0, T1> {
    using BaseLinkCutTree<T0, T1>::BaseLinkCutTree;
    SumAddQuery() : SumAddQuery(0, 0) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return x + y; }
    T0 g(T0 x, T1 y) override { return x + y; }
    T1 p(T1 x, int len) override { return x * len; }
};

template <class T0, class T1>
struct MinAddQuery : public BaseLinkCutTree<T0, T1> {
    using BaseLinkCutTree<T0, T1>::BaseLinkCutTree;
    MinAddQuery() : MinAddQuery(numeric_limits<T0>::max(), 0) {}
    T0 f0(T0 x, T0 y) override { return min(x, y); }
    T1 f1(T1 x, T1 y) override { return x + y; }
    T0 g(T0 x, T1 y) override { return x + y; }
    T1 p(T1 x, int len) override { return x; }
};

template <class T0, class T1>
struct SumUpdateQuery : public BaseLinkCutTree<T0, T1> {
    using BaseLinkCutTree<T0, T1>::BaseLinkCutTree;
    SumUpdateQuery() : SumUpdateQuery(0, numeric_limits<T1>::min()) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T0 g(T0 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T1 p(T1 x, int len) override { return x == numeric_limits<T1>::min() ? numeric_limits<T1>::min() : x * len; }
};

template <class T0>
struct SumAffineQuery : public BaseLinkCutTree<T0, pair<T0, T0>> {
    using T1 = pair<T0, T0>;  // first * x + second
    using BaseLinkCutTree<T0, T1>::BaseLinkCutTree;
    SumAffineQuery() : SumAffineQuery(0, {1, 0}) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return {x.first * y.first, x.second * y.first + y.second}; }
    T0 g(T0 x, T1 y) override { return y.first * x + y.second; }
    T1 p(T1 x, int len) override { return {x.first, x.second * len}; }
    // update(i, j, {a, b}); // [i, j)にax + bを作用
    // update(i, j, {0, a}); // update
    // update(i, j, {1, a}); // 加算
    // update(i, j, {a, 0}); // 倍
};

template <class T>
struct MinmaxAffineQuery : public BaseLinkCutTree<pair<T, T>, pair<T, T>> {
    using T0 = pair<T, T>;  // {min, max}
    using T1 = pair<T, T>;  // first * x + second
    using BaseLinkCutTree<T0, T1>::BaseLinkCutTree;
    MinmaxAffineQuery()
        : MinmaxAffineQuery({numeric_limits<T>::max(), -numeric_limits<T>::max()}, {1, 0}) {
    }  // TODO: _u1を使うとコンパイル通らない原因不明
    T0 f0(T0 x, T0 y) override { return {min(x.first, y.first), max(x.second, y.second)}; }
    T1 f1(T1 x, T1 y) override { return {x.first * y.first, x.second * y.first + y.second}; }
    T0 g(T0 x, T1 y) override {
        T0 ret = {x.first * y.first + y.second, x.second * y.first + y.second};
        if (y.first < 0) swap(ret.first, ret.second);
        return ret;
    }
    T1 p(T1 x, int len) override { return x; }
    // update(i, j, {a, b}); // [i, j)にax + bを作用
    // update(i, j, {0, a}); // update
    // update(i, j, {1, a}); // 加算
    // update(i, j, {a, 0}); // 倍
};

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

    SumAddQuery<int, int> lct;
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) lct.make_new_node(0);

    random_device rnd;

    for (int i = 0; i < n - 1; i++) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        lct.link(a, b);

        if (rnd() % 3 == 0) {
            // 適当に回転させて遊んでみる
            int sz = i + 1;
            int v = rnd() % sz;
            lct.evert(v);
        }
        if (i > 0 && rnd() % 5 == 0) {
            // 適当に切り離して遊んでみる
            int sz = i + 1;
            int v = rnd() % sz;
            int depth = lct.depth(v);
            if (depth > 0) {
                int u = lct.get_kth(v, 1);
                lct.cut(v);
                lct.link(u, v);
            }
        }
    }

    int q;
    cin >> q;
    long long ans = 0;
    while (q--) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        lct.update(a, b, 1);

        if (rnd() % 3 == 0) {
            // 適当に回転させて遊んでみる
            int v = rnd() % n;
            lct.evert(v);
        }
        if (rnd() % 5 == 0) {
            // 適当に切り離して遊んでみる
            int v = rnd() % n;
            int depth = lct.depth(v);
            if (depth > 0) {
                int u = lct.get_kth(v, 1);
                lct.cut(v);
                int w = rnd() % n;
                if (w != v && w != u) {
                    // さらに回転させて遊ぶ
                    lct.evert(w);
                }
                lct.link(u, v);
            }
        }
    }

    for (int i = 0; i < n; i++) {
        int k = lct.query(i);
        ans += 1LL * k * (k + 1) / 2;
    }

    cout << ans << endl;
}
0