CP-Algorithms Library

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

View the Project on GitHub cp-algorithms/cp-algorithms-aux

:heavy_check_mark: Build Cartesian Tree (verify/structures/treap/cartesian_tree.test.cpp)

Depends on

Code

// @brief Build Cartesian Tree
#define PROBLEM "https://judge.yosupo.jp/problem/cartesian_tree"
#include "cp-algo/structures/treap/metas/base.hpp"
#include "cp-algo/structures/treap.hpp"
#include <bits/stdc++.h>

using namespace std;
using namespace cp_algo::structures::treap;

struct val_meta: metas::base_meta {
    int val;
    val_meta(int val): val(val){}
};

using node_t = node<val_meta>;
using treap = node_t::treap;

void solve() {
    istream_iterator<int> input(cin);
    int n = *input++;
    cp_algo::big_vector<treap> nodes(n);
    for(int i = 0; i < n; i++) {
        nodes[i] = node_t::make_treap(val_meta(i), *input++);
    }
    auto me = node_t::build(nodes);
    cp_algo::big_vector<int> p(n, -1);
    node_t::exec_on_each(me, [&](auto t) {
        for(auto child: t->children) {
            if(child) {
                p[_safe_meta(child, val)] = _safe_meta(t, val);
            }
        }
    });
    for(int i = 0; i < n; i++) {
        cout << (p[i] == -1 ? i : p[i]) << ' ';
    }
}

signed main() {
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t = 1;
    while(t--) {
        solve();
    }
}
#line 1 "verify/structures/treap/cartesian_tree.test.cpp"
// @brief Build Cartesian Tree
#define PROBLEM "https://judge.yosupo.jp/problem/cartesian_tree"
#line 1 "cp-algo/structures/treap/metas/base.hpp"


#line 1 "cp-algo/structures/treap/common.hpp"


#define _safe(t, op) (t ? t->op : typename std::remove_reference_t<decltype(t->op)>())

#line 4 "cp-algo/structures/treap/metas/base.hpp"
#include <functional>
#include <algorithm>
#include <cstdint>
#define _safe_meta(i, op) _safe(i, _meta.op)
namespace cp_algo::structures::treap::metas {
    struct base_meta {
        void pull(auto const, auto const){}
        void push(auto&, auto&){}
    };
}

#line 1 "cp-algo/structures/treap.hpp"


#line 1 "cp-algo/util/big_alloc.hpp"



#include <set>
#include <map>
#include <deque>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <cstddef>
#include <iostream>
#include <generator>
#include <forward_list>

// Single macro to detect POSIX platforms (Linux, Unix, macOS)
#if defined(__linux__) || defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#  define CP_ALGO_USE_MMAP 1
#  include <sys/mman.h>
#else
#  define CP_ALGO_USE_MMAP 0
#endif

namespace cp_algo {
    template <typename T, size_t Align = 32>
    class big_alloc {
        static_assert( Align >= alignof(void*), "Align must be at least pointer-size");
        static_assert(std::popcount(Align) == 1, "Align must be a power of two");
    public:
        using value_type = T;
        template <class U> struct rebind { using other = big_alloc<U, Align>; };
        constexpr bool operator==(const big_alloc&) const = default;
        constexpr bool operator!=(const big_alloc&) const = default;

        big_alloc() noexcept = default;
        template <typename U, std::size_t A>
        big_alloc(const big_alloc<U, A>&) noexcept {}

        [[nodiscard]] T* allocate(std::size_t n) {
            std::size_t padded = round_up(n * sizeof(T));
            std::size_t align = std::max<std::size_t>(alignof(T),  Align);
#if CP_ALGO_USE_MMAP
            if (padded >= MEGABYTE) {
                void* raw = mmap(nullptr, padded,
                                PROT_READ | PROT_WRITE,
                                MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
                madvise(raw, padded, MADV_HUGEPAGE);
                madvise(raw, padded, MADV_POPULATE_WRITE);
                return static_cast<T*>(raw);
            }
#endif
            return static_cast<T*>(::operator new(padded, std::align_val_t(align)));
        }

        void deallocate(T* p, std::size_t n) noexcept {
            if (!p) return;
            std::size_t padded = round_up(n * sizeof(T));
            std::size_t align  = std::max<std::size_t>(alignof(T),  Align);
    #if CP_ALGO_USE_MMAP
            if (padded >= MEGABYTE) { munmap(p, padded); return; }
    #endif
            ::operator delete(p, padded, std::align_val_t(align));
        }

    private:
        static constexpr std::size_t MEGABYTE = 1 << 20;
        static constexpr std::size_t round_up(std::size_t x) noexcept {
            return (x + Align - 1) / Align * Align;
        }
    };

    template<typename T> using big_vector = std::vector<T, big_alloc<T>>;
    template<typename T> using big_basic_string = std::basic_string<T, std::char_traits<T>, big_alloc<T>>;
    template<typename T> using big_deque = std::deque<T, big_alloc<T>>;
    template<typename T> using big_stack = std::stack<T, big_deque<T>>;
    template<typename T> using big_queue = std::queue<T, big_deque<T>>;
    template<typename T> using big_priority_queue = std::priority_queue<T, big_vector<T>>;
    template<typename T> using big_forward_list = std::forward_list<T, big_alloc<T>>;
    using big_string = big_basic_string<char>;

    template<typename Key, typename Value, typename Compare = std::less<Key>>
    using big_map = std::map<Key, Value, Compare, big_alloc<std::pair<const Key, Value>>>;
    template<typename T, typename Compare = std::less<T>>
    using big_multiset = std::multiset<T, Compare, big_alloc<T>>;
    template<typename T, typename Compare = std::less<T>>
    using big_set = std::set<T, Compare, big_alloc<T>>;
    template<typename Ref, typename V = void>

    using big_generator = std::generator<Ref, V, big_alloc<std::byte>>;
}

// Deduction guide to make elements_of with big_generator default to big_alloc
namespace std::ranges {
    template<typename Ref, typename V>
    elements_of(cp_algo::big_generator<Ref, V>&&) -> elements_of<cp_algo::big_generator<Ref, V>&&, cp_algo::big_alloc<std::byte>>;
}


#line 1 "cp-algo/random/rng.hpp"


#include <chrono>
#include <random>
namespace cp_algo::random {
    std::mt19937_64 gen(
        std::chrono::steady_clock::now().time_since_epoch().count()
    );
    uint64_t rng() {
        return gen();
    }
}

#line 6 "cp-algo/structures/treap.hpp"
#include <array>
namespace cp_algo::structures::treap {
    template<typename meta>
    struct node {
        using treap = node*;
        meta _meta;
        int prior = (int)random::rng();
        size_t size = 1;
        treap children[2] = {nullptr, nullptr};
        enum subtree {L, R};

        node() {}
        node(meta _meta): _meta(_meta) {}
        node(meta _meta, int prior): _meta(_meta), prior(prior) {}

        static treap make_treap(auto...args) {
            return new node(args...);
        }

        treap pull() {
            _meta.pull(children[L], children[R]);
            size = 1 + _safe(children[L], size) + _safe(children[R], size);
            return this;
        }

        treap push() {
            _meta.push(children[L], children[R]);
            return this;
        }

        // set i-th child and pull metadata
        treap set(subtree i, treap t) {
            children[i] = t;
            return pull();
        }

        // push changes and detach the i-th child
        treap cut(subtree i) {
            return children[i];
        }

        static treap merge(treap A, treap B) {
            if(!_safe(A, push()) || !_safe(B, push())) {
                return A ? A : B;
            } else if(A->prior < B->prior) {
                return A->set(R, merge(A->cut(R), B));
            } else {
                return B->set(L, merge(A, B->cut(L)));
            }
        }

        // return {L, R}, where |L|=k or L=A when |A| < k
        static std::array<treap, 2> split(treap A, size_t k) {
            if(!_safe(A, push())) {
                return {nullptr, nullptr};
            } else if(_safe(A->children[L], size) >= k) {
                auto [split_L, split_R] = split(A->cut(L), k);
                return {split_L, A->set(L, split_R)};
            } else {
                k -= _safe(A->children[L], size) + 1;
                auto [split_L, split_R] = split(A->cut(R), k);
                return {A->set(R, split_L), split_R};
            }
        }

        static void exec_on_segment(treap &A, size_t l, size_t r, auto func) {
            auto [LM, R] = split(A, r);
            auto [L, M] = split(LM, l);
            func(M);
            A = merge(L, merge(M, R));
        }

        static void insert(treap &A, size_t pos, treap t) {
            auto [L, R] = split(A, pos);
            A = merge(L, merge(t, R));
        }

        static void erase(treap &A, size_t pos) {
            auto [L, MR] = split(A, pos);
            auto [M, R] = split(MR, 1);
            delete M;
            A = merge(L, R);
        }

        static void exec_on_each(treap &A, auto func) {
            if(A) {
                exec_on_each(A->children[L], func);
                func(A);
                exec_on_each(A->children[R], func);
            }
        }

        treap pull_all() {
            _safe(children[L], pull_all());
            _safe(children[R], pull_all());
            return pull();
        }

        treap push_all() {
            push();
            _safe(children[L], push_all());
            _safe(children[R], push_all());
            return this;
        }

        static treap build(auto const& nodes) {
            big_vector<treap> st;
            for(auto cur: nodes) {
                while(st.size() >= 2 && st[st.size() - 2]->prior > cur->prior) {
                    st.pop_back();
                }
                if(!st.empty() && st.back()->prior > cur->prior) {
                    cur->set(L, st.back());
                    st.pop_back();
                }
                if(!st.empty() && st.back()->prior < cur->prior) {
                    st.back()->set(R, cur);
                }
                st.push_back(cur);
            }
            return st.empty() ? nullptr : st[0]->pull_all();
        }
    };

    struct null_meta {
        void pull(auto const, auto const) {}
        void push(auto&, auto&) {}
    };
}

#line 5 "verify/structures/treap/cartesian_tree.test.cpp"
#include <bits/stdc++.h>

using namespace std;
using namespace cp_algo::structures::treap;

struct val_meta: metas::base_meta {
    int val;
    val_meta(int val): val(val){}
};

using node_t = node<val_meta>;
using treap = node_t::treap;

void solve() {
    istream_iterator<int> input(cin);
    int n = *input++;
    cp_algo::big_vector<treap> nodes(n);
    for(int i = 0; i < n; i++) {
        nodes[i] = node_t::make_treap(val_meta(i), *input++);
    }
    auto me = node_t::build(nodes);
    cp_algo::big_vector<int> p(n, -1);
    node_t::exec_on_each(me, [&](auto t) {
        for(auto child: t->children) {
            if(child) {
                p[_safe_meta(child, val)] = _safe_meta(t, val);
            }
        }
    });
    for(int i = 0; i < n; i++) {
        cout << (p[i] == -1 ? i : p[i]) << ' ';
    }
}

signed main() {
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t = 1;
    while(t--) {
        solve();
    }
}

Test cases

Env Name Status Elapsed Memory
g++ almost-decreasing_00 :heavy_check_mark: AC 152 ms 85 MB
g++ almost-decreasing_01 :heavy_check_mark: AC 70 ms 41 MB
g++ almost-increasing_00 :heavy_check_mark: AC 157 ms 90 MB
g++ almost-increasing_01 :heavy_check_mark: AC 72 ms 44 MB
g++ decreasing_00 :heavy_check_mark: AC 160 ms 85 MB
g++ decreasing_01 :heavy_check_mark: AC 70 ms 41 MB
g++ example_00 :heavy_check_mark: AC 4 ms 4 MB
g++ example_01 :heavy_check_mark: AC 3 ms 4 MB
g++ increasing_00 :heavy_check_mark: AC 151 ms 90 MB
g++ increasing_01 :heavy_check_mark: AC 71 ms 44 MB
g++ random_00 :heavy_check_mark: AC 158 ms 62 MB
g++ random_01 :heavy_check_mark: AC 74 ms 31 MB
g++ random_02 :heavy_check_mark: AC 92 ms 37 MB
g++ random_03 :heavy_check_mark: AC 71 ms 29 MB
g++ random_04 :heavy_check_mark: AC 130 ms 50 MB
g++ small_00 :heavy_check_mark: AC 4 ms 4 MB
g++ small_01 :heavy_check_mark: AC 3 ms 4 MB
g++ small_02 :heavy_check_mark: AC 3 ms 4 MB
g++ small_03 :heavy_check_mark: AC 3 ms 4 MB
g++ small_04 :heavy_check_mark: AC 3 ms 4 MB
g++ small_05 :heavy_check_mark: AC 3 ms 4 MB
g++ small_06 :heavy_check_mark: AC 3 ms 4 MB
g++ small_07 :heavy_check_mark: AC 3 ms 4 MB
g++ small_08 :heavy_check_mark: AC 3 ms 4 MB
g++ small_09 :heavy_check_mark: AC 3 ms 4 MB
Back to top page