Skip to the content.

:heavy_check_mark: Link-Cut Tree (data_structure/link_cut_tree.hpp)

動的な木に対する操作(辺の追加・削除、パス上の集約値取得など)を高速に行うことができるデータ構造です。

テンプレートパラメータ:

使い方

add

void add(T x)

説明

新しいノードに値 x を追加します。ノードのインデックスは追加された順に0から割り当てられます。

計算量

$O(1)$

void link(int u, int v)

説明

ノード u とノード v の間に辺を追加し、2つの木を連結します。u は根である必要があります。

制約

計算量

$O(\log N)$ (amortized)

expose

void expose(nptr& ptr)

説明

ノード ptr をその属する木の根からの優先パスの最上部に持ち上げます。これにより、根から ptr までのパスがSplay Treeとして表現されます。

計算量

$O(\log N)$ (amortized)

evert

void evert(nptr ptr)

説明

ノード ptr をその属する木の新しい根とします。

計算量

$O(\log N)$ (amortized)

cut

void cut(int U, int V)

説明

ノード U とノード V の間の辺を削除します。UV の親である必要があります。

制約

計算量

$O(\log N)$ (amortized)

set

void set(int U, T x)

説明

ノード U の値を x に更新します。

計算量

$O(\log N)$ (amortized)

operator[]

T operator[](int U)

説明

ノード U の値を返します。

計算量

$O(\log N)$ (amortized)

operator()

T operator()(int U, int V)

説明

ノード U とノード V の間のパス上の値の集約結果を返します。U を根とする木において、V までのパスの集約値を取得します。

制約

計算量

$O(\log N)$ (amortized)

Depends on

Verified with

Code

#pragma once
#include <cstdint>
#include <data_structure/splay_tree.hpp>
#include <vector>

template <typename T, auto op, auto e>
struct LinkCutTree : public SplayTree<T, op, e> {
    using Splay = SplayTree<T, op, e>;
    using nptr = Splay::nptr;
    std::vector<nptr> node;

    LinkCutTree() {}
    LinkCutTree(int n) {
        for (int i = 0; i < n; i++) {
            add(e());
        }
    }
    LinkCutTree(const std::vector<std::vector<int>>& g) : LinkCutTree(g, std::vector<T>(g.size(), e())) {}
    LinkCutTree(const std::vector<std::vector<int>>& g, const std::vector<T>& v) {
        for (uint32_t i = 0, siz = v.size(); i < siz; ++i) {
            add(v[i]);
        }
        for (int u = 0, siz = v.size(); u < siz; ++u) {
            for (int v : g[u]) {
                if (u > v) continue;
                link(u, v);
            }
        }
    }

    void add(T x) {
        node.emplace_back(new Splay::node{x, static_cast<int>(node.size())});
    }

    int expose(nptr& ptr) {
        nptr last = ptr;
        while (true) {
            Splay::splay(ptr);
            ptr->right = nullptr;
            Splay::update(ptr);
            if (!ptr->parent) {
                return last->idx;
            }
            last = ptr->parent;
            Splay::splay(ptr->parent);
            ptr->parent->right = ptr;
            Splay::update(ptr->parent);
        }
    }

    void evert(nptr ptr) {
        expose(ptr);
        Splay::toggle(ptr);
    }

    void link(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        evert(v);
        v->parent = u;
    }

    void cut(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        evert(u);
        expose(v);
        v->left->parent = nullptr;
        v->left = nullptr;
        Splay::update(v);
    }

    void set(int U, T x) {
        nptr u = node[U];
        expose(u);
        u->v = x;
        Splay::update(u);
    }

    T operator[](int U) {
        nptr u = node[U];
        expose(u);
        return u->v;
    }

    T operator()(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        evert(u);
        expose(v);
        return v->p;
    }

    int lca(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        expose(u);
        return expose(v);
    }
};
#line 2 "data_structure/link_cut_tree.hpp"
#include <cstdint>
#include <data_structure/splay_tree.hpp>
#include <vector>

template <typename T, auto op, auto e>
struct LinkCutTree : public SplayTree<T, op, e> {
    using Splay = SplayTree<T, op, e>;
    using nptr = Splay::nptr;
    std::vector<nptr> node;

    LinkCutTree() {}
    LinkCutTree(int n) {
        for (int i = 0; i < n; i++) {
            add(e());
        }
    }
    LinkCutTree(const std::vector<std::vector<int>>& g) : LinkCutTree(g, std::vector<T>(g.size(), e())) {}
    LinkCutTree(const std::vector<std::vector<int>>& g, const std::vector<T>& v) {
        for (uint32_t i = 0, siz = v.size(); i < siz; ++i) {
            add(v[i]);
        }
        for (int u = 0, siz = v.size(); u < siz; ++u) {
            for (int v : g[u]) {
                if (u > v) continue;
                link(u, v);
            }
        }
    }

    void add(T x) {
        node.emplace_back(new Splay::node{x, static_cast<int>(node.size())});
    }

    int expose(nptr& ptr) {
        nptr last = ptr;
        while (true) {
            Splay::splay(ptr);
            ptr->right = nullptr;
            Splay::update(ptr);
            if (!ptr->parent) {
                return last->idx;
            }
            last = ptr->parent;
            Splay::splay(ptr->parent);
            ptr->parent->right = ptr;
            Splay::update(ptr->parent);
        }
    }

    void evert(nptr ptr) {
        expose(ptr);
        Splay::toggle(ptr);
    }

    void link(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        evert(v);
        v->parent = u;
    }

    void cut(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        evert(u);
        expose(v);
        v->left->parent = nullptr;
        v->left = nullptr;
        Splay::update(v);
    }

    void set(int U, T x) {
        nptr u = node[U];
        expose(u);
        u->v = x;
        Splay::update(u);
    }

    T operator[](int U) {
        nptr u = node[U];
        expose(u);
        return u->v;
    }

    T operator()(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        evert(u);
        expose(v);
        return v->p;
    }

    int lca(int U, int V) {
        nptr u = node[U];
        nptr v = node[V];
        expose(u);
        return expose(v);
    }
};
Back to top page