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: cp-algo/structures/treap.hpp

Depends on

Verified with

Code

#ifndef CP_ALGO_STRUCTURES_TREAP_HPP
#define CP_ALGO_STRUCTURES_TREAP_HPP
#include "../util/big_alloc.hpp"
#include "../random/rng.hpp"
#include "treap/common.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&) {}
    };
}
#endif // CP_ALGO_STRUCTURES_TREAP_HPP
#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 <bit>
#include <iostream>
#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::has_single_bit(Align), "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;

        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);
                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>>;
}


#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 1 "cp-algo/structures/treap/common.hpp"


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

#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&) {}
    };
}

#ifndef CP_ALGO_STRUCTURES_TREAP_HPP
#define CP_ALGO_STRUCTURES_TREAP_HPP
#include "../util/big_alloc.hpp"
#include "../random/rng.hpp"
#include "treap/common.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; } treap set(subtree i,treap t){ children[i] =t; return pull(); } 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))); } } 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&){} }; }
#endif
#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 <bit>
#include <iostream>
#include <forward_list>
#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::has_single_bit(Align),"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; 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); 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>>; }
#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 1 "cp-algo/structures/treap/common.hpp"
#define _safe(t, op) (t ? t->op : typename std::remove_reference_t<decltype(t->op)>())
#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; } treap set(subtree i,treap t){ children[i] =t; return pull(); } 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))); } } 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&){} }; }
Back to top page