firiexp's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub firiexp/library

:heavy_check_mark: Virtual Tree Helper
(tree/virtual_tree_helper.cpp)

説明

AuxTreemake / clear / out 管理を隠して、DP しやすい形で virtual tree を返す補助ラッパ。 各クエリごとに、必要頂点と補われた LCA 頂点からなる根付き木を作る。

できること

使い方

make の返り値は vertices[i] とその親 parent[i] を持つ。 parent[i] = -1 の頂点が根で、i は親が子より先に出る。 部分木 DP は vertices を逆順に走査すればよい。

auto tr = vt.make(query_vertices);
for (int i = (int)tr.vertices.size() - 1; i >= 0; --i) {
    int v = tr.vertices[i];
    int p = tr.parent[i];
    if (p != -1) {
        // v -> p に畳み込む
    }
}

実装上の補足

返り値の頂点列には元の query 頂点に加えて必要な LCA 頂点も入る。 内部では AuxTree を使い、各クエリ後の clear は helper 側で処理する。

Depends on

Verified with

Code

#include "./auxtree.cpp"

struct VirtualTree {
    int root;
    vector<int> vertices;
    vector<int> parent;
};

class VirtualTreeHelper {
    AuxTree aux;
    vector<int> mark, parent_buf;
    int stamp = 0;

public:
    explicit VirtualTreeHelper(int n) : aux(n), mark(n, 0), parent_buf(n, -1) {}

    void add_edge(int u, int v) {
        aux.add_edge(u, v);
    }

    void build(int root = 0) {
        aux.buildLCA(root);
    }

    int lca(int u, int v) {
        return aux.LCA(u, v);
    }

    int distance(int u, int v) {
        return aux.distance(u, v);
    }

    VirtualTree make(vector<int> vertices) {
        aux.make(vertices);
        sort(vertices.begin(), vertices.end(), [&](int a, int b) { return aux.fi[a] < aux.fi[b]; });
        vertices.erase(unique(vertices.begin(), vertices.end()), vertices.end());

        VirtualTree res;
        res.root = vertices.front();
        ++stamp;
        vector<int> st = {res.root};
        mark[res.root] = stamp;
        parent_buf[res.root] = -1;

        while (!st.empty()) {
            int v = st.back();
            st.pop_back();
            res.vertices.emplace_back(v);
            res.parent.emplace_back(parent_buf[v]);
            for (auto &&u : aux.out[v]) {
                if (mark[u] == stamp) continue;
                mark[u] = stamp;
                parent_buf[u] = v;
                st.emplace_back(u);
            }
        }

        aux.clear(vertices);
        return res;
    }
};

/**
 * @brief Virtual Tree Helper
 */
#line 1 "datastructure/sparsetable.cpp"
template <class F>
struct SparseTable {
    using T = typename F::T;
    vector<vector<T>> table;
    vector<int> u;
    SparseTable() = default;
    explicit SparseTable(const vector<T> &v){ build(v); }
 
    void build(const vector<T> &v){
        int n = v.size(), m = 1;
        while((1<<m) <= n) m++;
        table.assign(m, vector<T>(n));
        u.assign(n+1, 0);
        for (int i = 2; i <= n; ++i) {
            u[i] = u[i>>1] + 1;
        }
        for (int i = 0; i < n; ++i) {
            table[0][i] = v[i];
        }
        for (int i = 1; i < m; ++i) {
            int x = (1<<(i-1));
            for (int j = 0; j < n; ++j) {
                table[i][j] = F::f(table[i-1][j], table[i-1][min(j+x, n-1)]);
            }
        }
    }
 
    T query(int a, int b){
        int l = b-a;
        return F::f(table[u[l]][a], table[u[l]][b-(1<<u[l])]);
    }
};

/**
 * @brief Sparse Table
 */
#line 2 "tree/auxtree.cpp"

struct F {
    using T = pair<int, int>;
    static T f(T a, T b) { return min(a, b); }
    static T e() { return T{INF<int>, -1}; }
};

class AuxTree {
    SparseTable<F> table;
    void dfs_euler(int v, int p, int d, int &k, int &l){
        id[v] = k;
        vs[k] = v;
        depth[k++] = d;
        dep[v] = d;
        fi[v] = l++;
        for (auto &&u : G[v]) {
            if(u != p){
                dfs_euler(u, v, d+1, k, l);
                vs[k] = v;
                depth[k++] = d;
            }
        }
    }
public:
    int n;
    vector<vector<int>> G, out;
    vector<int> vs, depth, dep, id, fi;
    explicit AuxTree(int n) : table(), n(n), G(n), out(n), vs(2*n-1), depth(2*n-1), dep(n), id(n), fi(n) {};
    void add_edge(int a, int b){
        G[a].emplace_back(b);
        G[b].emplace_back(a);
    }

    void eulertour(int root) {
        int k = 0, l = 0;
        dfs_euler(root, -1, 0, k, l);
    }

    void buildLCA(int root = 0){
        eulertour(root);
        vector<pair<int, int>> v(2*n-1);
        for (int i = 0; i < 2*n-1; ++i) {
            v[i] = make_pair(depth[i], vs[i]);
        }
        table.build(v);
    }

    void make(vector<int> &v){
        sort(v.begin(),v.end(), [&](int a, int b){ return fi[a] < fi[b]; });
        v.erase(unique(v.begin(), v.end()), v.end());
        int k = v.size();
        stack<int> s;
        s.emplace(v.front());
        for (int i = 0; i+1 < k; ++i) {
            int w = LCA(v[i], v[i+1]);
            if(w != v[i]){
                int u = s.top(); s.pop();
                while(!s.empty() && dep[w] < dep[s.top()]){
                    out[s.top()].emplace_back(u);
                    out[u].emplace_back(s.top());
                    u = s.top(); s.pop();
                }
                if(s.empty() || s.top() != w){
                    s.emplace(w);
                    v.emplace_back(w);
                }
                out[w].emplace_back(u);
                out[u].emplace_back(w);
            }
            s.emplace(v[i+1]);
        }
        while(s.size() > 1){
            int u = s.top(); s.pop();
            out[s.top()].emplace_back(u);
            out[u].emplace_back(s.top());
        }
    }

    void clear(vector<int> &v){
        for (auto &&i : v) {
            out[i].clear();
            out[i].shrink_to_fit();
        }
    }

    int LCA(int u, int v){
        if(id[u] > id[v]) swap(u, v);
        return table.query(id[u], id[v]+1).second;
    }

    int distance(int u, int v){
        return dep[u]+dep[v]-2*dep[LCA(u, v)];
    }
};

/**
 * @brief 補助木(Aux Tree)
 */
#line 2 "tree/virtual_tree_helper.cpp"

struct VirtualTree {
    int root;
    vector<int> vertices;
    vector<int> parent;
};

class VirtualTreeHelper {
    AuxTree aux;
    vector<int> mark, parent_buf;
    int stamp = 0;

public:
    explicit VirtualTreeHelper(int n) : aux(n), mark(n, 0), parent_buf(n, -1) {}

    void add_edge(int u, int v) {
        aux.add_edge(u, v);
    }

    void build(int root = 0) {
        aux.buildLCA(root);
    }

    int lca(int u, int v) {
        return aux.LCA(u, v);
    }

    int distance(int u, int v) {
        return aux.distance(u, v);
    }

    VirtualTree make(vector<int> vertices) {
        aux.make(vertices);
        sort(vertices.begin(), vertices.end(), [&](int a, int b) { return aux.fi[a] < aux.fi[b]; });
        vertices.erase(unique(vertices.begin(), vertices.end()), vertices.end());

        VirtualTree res;
        res.root = vertices.front();
        ++stamp;
        vector<int> st = {res.root};
        mark[res.root] = stamp;
        parent_buf[res.root] = -1;

        while (!st.empty()) {
            int v = st.back();
            st.pop_back();
            res.vertices.emplace_back(v);
            res.parent.emplace_back(parent_buf[v]);
            for (auto &&u : aux.out[v]) {
                if (mark[u] == stamp) continue;
                mark[u] = stamp;
                parent_buf[u] = v;
                st.emplace_back(u);
            }
        }

        aux.clear(vertices);
        return res;
    }
};

/**
 * @brief Virtual Tree Helper
 */
Back to top page