imsuck's library

This documentation is automatically generated by competitive-verifier/competitive-verifier

View the Project on GitHub imsuck/library

:heavy_check_mark: test/yosupo/graph/incremental_minimum_spanning_forest.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/incremental_minimum_spanning_forest"

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

#include "tree/link_cut.hpp"

struct node : lct_node<node> {
    using lct_node<node>::lct_node;

    pair<int, int> val{0, -1}, path{0, -1};

    void pull() { path = max({$(l)->path, val, $(r)->path}); }

    void set(pair<int, int> a) { val = a; }
};

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    LCT<node> tr(n + m);
    vector<int> v(m), u(m);
    for (int i = 0, w; i < m; i++) {
        cin >> u[i] >> v[i] >> w;
        tr.set(i + n, pair{w, i});
        int ans = -1;
        if (u[i] == v[i]) {
            cout << i << "\n";
            continue;
        }
        if (tr.lca(u[i], v[i]) == -1) {
            cout << -1 << " \n"[i == m - 1];
            tr.link(u[i], i + n);
            tr.link(v[i], i + n);
            continue;
        }
        tr.expose_path(u[i], v[i]);
        auto [mx, id] = tr[v[i]]->path;
        if (w > mx) {
            ans = i;
        } else {
            ans = id;
            tr.cut(u[id], id + n), tr.cut(v[id], id + n);
        }
        cout << ans << " \n"[i == m - 1];
        if (ans != i) {
            tr.link(u[i], i + n);
            tr.link(v[i], i + n);
        }
    }
}
#line 1 "test/yosupo/graph/incremental_minimum_spanning_forest.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/incremental_minimum_spanning_forest"

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

#line 2 "tree/link_cut.hpp"

template<class node> struct LCT {
    using ptr = node *;
    vector<node> nodes;

    LCT(int n = 0) : nodes(n) {}

    auto operator[](int i) { return &nodes[i]; }
    int id(ptr t) { return int(t - &nodes[0]); }

    void splay(int v) { splay(&nodes[v]); }
    void expose(int v) { expose(&nodes[v]); }
    void expose_path(int u, int v) { evert(u), expose(v); }
    void evert(int v) { evert(&nodes[v]); }
    void link(int v, int p) { link(&nodes[v], &nodes[p]); }
    void cut(int v, int p) { cut(&nodes[v], &nodes[p]); }
    int lca(int u, int v) {
        ptr l = lca(&nodes[u], &nodes[v]);
        return l ? id(l) : -1;
    }
    template<class... T> void set(int v, T &&...x) {
        expose(v), nodes[v].set(x...);
    }
    template<class... T> void add(int v, T &&...x) {
        expose(v), nodes[v].add(x...);
    }

    static void splay(ptr t) {
        for (t->_push(); state(t); rot(t)) {
            ptr p = t->p, g = p->p;
            if (g) g->_push();
            p->_push(), t->_push();
            if (state(p)) rot(state(t) == state(p) ? p : t);
        }
    }
    static ptr expose(ptr t) {
        ptr prv = 0;
        for (ptr cur = t; cur; cur = cur->p) {
            splay(cur);
            if (cur->r) cur->_add_light(cur->r);
            if (prv) cur->_sub_light(prv);
            attach(cur, 1, exchange(prv, cur));
        }
        splay(t);
        return prv;
    }
    static void evert(ptr t) { expose(t), t->_flip(); }
    static void link(ptr v, ptr p) {
        evert(v), expose(p);
        assert(!v->p && !p->r);
        attach(p, 1, v);
    }
    static void cut(ptr v, ptr p) {
        evert(p), expose(v);
        assert(!v->p && v->l == p);
        attach(v, 0, p->p = 0);
    }
    static ptr lca(ptr u, ptr v) {
        if (u == v) return u;
        expose(u);
        ptr l = expose(v);
        return u->p ? l : 0;
    }

    static ptr &ch(ptr t, bool d) { return d ? t->r : t->l; }
    static void attach(ptr p, int d, ptr c) {
        if (c) c->p = p;
        ch(p, d) = c, p->pull();
    }
    static int state(ptr t) {
        if (!t->p) return 0;
        return t == t->p->l ? -1 : t == t->p->r ? 1 : 0;
    }
    static void rot(ptr t) {
        ptr p = t->p, g = p->p;
        int d = state(t) == 1, dp = state(p);
        t->p = p->p;
        if (g) dp ? attach(g, dp == 1, t) : g->_change_light(p, t);
        attach(p, d, ch(t, !d));
        attach(t, !d, p);
    }
};

template<class node> struct lct_node {
    using ptr = node *;
    static ptr $(ptr t) {
        static node nil;
        return t ?: &nil;
    }
    ptr p = 0, l = 0, r = 0;
    bool rev = 0;

    node *as_derived() { return (node *)this; };
    void _push() {
        if (exchange(rev, 0)) $(l)->_flip(), $(r)->_flip();
        if constexpr (has_push<node>) as_derived()->push();
    }
    void _flip() {
        swap(l, r), rev ^= 1;
        if constexpr (has_flip<node>) as_derived()->flip();
    }

    void _add_light(ptr c) {
        if constexpr (has_add_light<node>) as_derived()->add_light(c);
    }
    void _sub_light(ptr c) {
        if constexpr (has_sub_light<node>) as_derived()->sub_light(c);
    }
    void _change_light(ptr prv, ptr cur) {
        if constexpr (has_change_light<node>)
            as_derived()->change_light(prv, cur);
    }

// rip compile time
#define CHECK(a) \
    template<class T, class = void> struct has_##a##_t : false_type {}; \
    template<class T> struct has_##a##_t<T, void_t<decltype(&T::a)>> : true_type {}; \
    template<class T> static constexpr bool has_##a = has_##a##_t<T>::value;
    CHECK(push) CHECK(flip)
    CHECK(add_light) CHECK(sub_light) CHECK(change_light)
#undef CHECK
};
#line 7 "test/yosupo/graph/incremental_minimum_spanning_forest.test.cpp"

struct node : lct_node<node> {
    using lct_node<node>::lct_node;

    pair<int, int> val{0, -1}, path{0, -1};

    void pull() { path = max({$(l)->path, val, $(r)->path}); }

    void set(pair<int, int> a) { val = a; }
};

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    LCT<node> tr(n + m);
    vector<int> v(m), u(m);
    for (int i = 0, w; i < m; i++) {
        cin >> u[i] >> v[i] >> w;
        tr.set(i + n, pair{w, i});
        int ans = -1;
        if (u[i] == v[i]) {
            cout << i << "\n";
            continue;
        }
        if (tr.lca(u[i], v[i]) == -1) {
            cout << -1 << " \n"[i == m - 1];
            tr.link(u[i], i + n);
            tr.link(v[i], i + n);
            continue;
        }
        tr.expose_path(u[i], v[i]);
        auto [mx, id] = tr[v[i]]->path;
        if (w > mx) {
            ans = i;
        } else {
            ans = id;
            tr.cut(u[id], id + n), tr.cut(v[id], id + n);
        }
        cout << ans << " \n"[i == m - 1];
        if (ans != i) {
            tr.link(u[i], i + n);
            tr.link(v[i], i + n);
        }
    }
}

Test cases

Env Name Status Elapsed Memory
g++ example_00 :heavy_check_mark: AC 4 ms 4 MB
g++ hack_decreasing_00 :heavy_check_mark: AC 559 ms 82 MB
g++ max_random_00 :heavy_check_mark: AC 1926 ms 82 MB
g++ max_random_01 :heavy_check_mark: AC 410 ms 58 MB
g++ max_random_02 :heavy_check_mark: AC 950 ms 58 MB
g++ max_random_03 :heavy_check_mark: AC 1942 ms 82 MB
g++ max_random_04 :heavy_check_mark: AC 1921 ms 82 MB
g++ max_random_05 :heavy_check_mark: AC 404 ms 58 MB
g++ max_random_06 :heavy_check_mark: AC 938 ms 58 MB
g++ max_random_07 :heavy_check_mark: AC 410 ms 58 MB
g++ max_random_08 :heavy_check_mark: AC 401 ms 58 MB
g++ max_random_09 :heavy_check_mark: AC 1920 ms 82 MB
g++ random_00 :heavy_check_mark: AC 482 ms 44 MB
g++ random_01 :heavy_check_mark: AC 403 ms 48 MB
g++ random_02 :heavy_check_mark: AC 1526 ms 55 MB
g++ random_03 :heavy_check_mark: AC 796 ms 54 MB
g++ random_04 :heavy_check_mark: AC 40 ms 22 MB
clang++ example_00 :heavy_check_mark: AC 4 ms 4 MB
clang++ hack_decreasing_00 :heavy_check_mark: AC 562 ms 82 MB
clang++ max_random_00 :heavy_check_mark: AC 2085 ms 82 MB
clang++ max_random_01 :heavy_check_mark: AC 432 ms 58 MB
clang++ max_random_02 :heavy_check_mark: AC 1036 ms 58 MB
clang++ max_random_03 :heavy_check_mark: AC 2004 ms 82 MB
clang++ max_random_04 :heavy_check_mark: AC 2040 ms 82 MB
clang++ max_random_05 :heavy_check_mark: AC 441 ms 58 MB
clang++ max_random_06 :heavy_check_mark: AC 1025 ms 58 MB
clang++ max_random_07 :heavy_check_mark: AC 434 ms 58 MB
clang++ max_random_08 :heavy_check_mark: AC 438 ms 58 MB
clang++ max_random_09 :heavy_check_mark: AC 2039 ms 82 MB
clang++ random_00 :heavy_check_mark: AC 506 ms 44 MB
clang++ random_01 :heavy_check_mark: AC 423 ms 48 MB
clang++ random_02 :heavy_check_mark: AC 1629 ms 55 MB
clang++ random_03 :heavy_check_mark: AC 837 ms 54 MB
clang++ random_04 :heavy_check_mark: AC 41 ms 22 MB
Back to top page