c++ sparsetable 模版

闭区间查询

支持
区间最大
区间最小
区间和
区间最大下标
区间最小下标

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

#ifndef NO_UNIQUE_ADDRESS
#    ifdef __has_cpp_attribute
#        if __has_cpp_attribute(no_unique_address)
#            define NO_UNIQUE_ADDRESS [[no_unique_address]]
#        endif
#    endif
#    ifndef NO_UNIQUE_ADDRESS
#        define NO_UNIQUE_ADDRESS
#    endif
#endif // !NO_UNIQUE_ADDRESS

namespace details {
    inline unsigned int bsf32(uint32_t n) noexcept {
#if defined __GNUC__
        return __builtin_ctz(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanForward(&ans, n);
        return ans;
#elif
        static constexpr unsigned char table[32] = {
            0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
            31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
        };
        return table[((n & -n) * 0x077CB531) >> 57];
#endif
    }

    inline unsigned int bsf64(uint64_t n) noexcept {
#if defined __GNUC__
        return __builtin_ctzll(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanForward64(&ans, n);
        return ans;
#elif
        static constexpr unsigned char table[64] = {
            0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
            62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
            63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
            54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
        };
        return table[((n & -n) * 0x03f79d71b4ca8b09) >> 58];
#endif
    }

    inline unsigned int bsr32(uint32_t n) noexcept {
#if defined __GNUC__
        return 31 - __builtin_clz(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanReverse(&ans, n);
        return ans;
#elif
        float t = n;
        uint32_t ans;
        memcpy(&ans, &t, sizeof(float));
        return (ans >> 23 & 255) - 127;
#endif
    }

    inline unsigned int bsr64(uint64_t n) noexcept {
#if defined __GNUC__
        return 63 - __builtin_clzll(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanReverse64(&ans, n);
        return ans;
#elif
        float t = n;
        uint32_t ans;
        memcpy(&ans, &t, sizeof(float));
        return (ans >> 23 & 255) - 127;
#endif
    }

    inline unsigned int popcnt32(uint32_t n) noexcept {
#if defined __GNUC__
        return __builtin_popcount(n);
#elif defined _MSC_VER
        return __popcnt(n);
#elif
        n -= ((n >> 1) & 0x55555555);
        n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
        return ((((n >> 4) + n) & 0x0f0f0f0f) * 0x01010101) >> 24;
#endif
    }

    inline unsigned int popcnt64(uint64_t n) noexcept {
#if defined __GNUC__
        return __builtin_popcountll(n);
#elif defined _MSC_VER
        return __popcnt64(n);
#elif
        n -= ((n >> 1) & 0x5555555555555555);
        n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333);
        return ((((n >> 4) + n) & 0x0f0f0f0f0f0f0f0f) * 0x0101010101010101) >> 56;
#endif
    }

    inline unsigned int parity32(uint32_t n) noexcept {
#if defined __GNUC__
        return __builtin_parity(n);
#elif defined _MSC_VER
        return __popcnt(n) & 1;
#elif
        n ^= n >> 1;
        n ^= n >> 2;
        n = (n & 0x11111111) * 0x11111111;
        return (n >> 28) & 1;
#endif
    }

    inline unsigned int parity64(uint64_t n) noexcept {
#if defined __GNUC__
        return __builtin_parityll(n);
#elif defined _MSC_VER
        return __popcnt64(n) & 1;
#elif
        n ^= n >> 1;
        n ^= n >> 2;
        n = (n & 0x1111111111111111) * 0x1111111111111111;
        return (n >> 60) & 1;
#endif
    }


    template<typename I, bool B = 32 < std::numeric_limits<I>::digits>
    struct _BitFuncImpl {
        inline static unsigned int bsf(I n) noexcept { return bsf64(n); }
        inline static unsigned int bsr(I n) noexcept { return bsr64(n); }
        inline static unsigned int popcnt(I n) noexcept { return popcnt64(n); }
        inline static unsigned int parity(I n) noexcept { return parity64(n); }
    };

    template<typename I>
    struct _BitFuncImpl<I, false> {
        inline static unsigned int bsf(I n) noexcept { return bsf32(n); }
        inline static unsigned int bsr(I n) noexcept { return bsr32(n); }
        inline static unsigned int popcnt(I n) noexcept { return popcnt32(n); }
        inline static unsigned int parity(I n) noexcept { return parity32(n); }
    };

    template<typename I>
    inline unsigned int bsf(I n) noexcept { return _BitFuncImpl<I>::bsf(n); }
    template<typename I>
    inline unsigned int bsr(I n) noexcept { return _BitFuncImpl<I>::bsr(n); }
    template<typename I>
    inline unsigned int popcnt(I n) noexcept { return _BitFuncImpl<I>::popcnt(n); }
    template<typename I>
    inline unsigned int parity(I n) noexcept { return _BitFuncImpl<I>::parity(n); }

    template<typename T, size_t K = 0, bool = std::is_empty<T>::value && !std::is_final<T>::value>
    struct Derivable {
    private:
        T val;
    public:
        constexpr Derivable() = default;
        template<typename... Args>
        constexpr Derivable(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value) : val(std::forward<Args>(args)...) {}
        inline constexpr T& value() noexcept { return val; }
        inline constexpr const T& value() const noexcept { return val; }
    };

    template<typename T, size_t K>
    struct Derivable<T, K, true> : private T {
        constexpr Derivable() = default;
        template<typename... Args>
        constexpr Derivable(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value) : T(std::forward<Args>(args)...) {}
        inline constexpr T& value() noexcept { return *this; }
        inline constexpr const T& value() const noexcept { return *this; }
    };

    template<typename Alloc>
    struct InitializerIterator {
        using traits = std::allocator_traits<Alloc>;
        using pointer = typename traits::pointer;
        using value_type = typename traits::value_type;
        InitializerIterator(const InitializerIterator&) = delete;
        InitializerIterator(InitializerIterator&& other) noexcept
                : ptr(other.ptr), cur(other.cur), p_alloc(other.p_alloc)
        {
            other.ptr = other.cur = nullptr;
            other.p_alloc = nullptr;
        }
        InitializerIterator(pointer ptr, Alloc& alloc) noexcept : ptr(ptr), cur(ptr), p_alloc(&alloc) {}
        ~InitializerIterator() noexcept {
            if (!std::is_trivially_destructible<value_type>::value)
                for (pointer it = ptr;it != cur;++it)
                    traits::destroy(*p_alloc, std::addressof(*it));
        }
        inline pointer release() noexcept {
            return ptr = cur;
        }
        inline InitializerIterator& operator*() noexcept { return *this; }
        inline InitializerIterator& operator++() noexcept { return *this; }
        inline InitializerIterator& operator++(int) noexcept { return *this;  }
        InitializerIterator& operator=(const InitializerIterator&) = delete;
        InitializerIterator& operator=(InitializerIterator&& other) noexcept {
            ptr = other.ptr;
            cur = other.cur;
            p_alloc = other.p_alloc;
            other.ptr = other.cur = nullptr;
            other.p_alloc = nullptr;
            return *this;
        }
        template<typename T>
        inline InitializerIterator& operator=(T&& val) noexcept(noexcept(std::is_nothrow_constructible<value_type, T&&>::value)) {
            traits::construct(*p_alloc, std::addressof(*cur), std::forward<T>(val));
            ++cur;
            return *this;
        }
    private:
        pointer ptr, cur;
        Alloc* p_alloc;
    };
}

template<typename TableIt, typename OutIt, typename Op>
inline OutIt make_sparse_table(TableIt st, size_t n, OutIt it, const Op& op = {}) {
    TableIt pre = std::move(st);
    for (size_t i = 2;i <= n;i *= 2) {
        for (size_t j = 0;j <= n - i;++j)
            *it++ = op(pre[j], pre[j + i / 2]);
        pre += n + 1 - i / 2;
    }
    return std::move(it);
}

inline size_t sparse_table_size(size_t n) {
    const size_t h = details::bsr(n) + size_t(1);
    return n * h + h + size_t(1) - (size_t(1) << h);
}

template<typename TableIt, typename Op>
inline typename std::iterator_traits<TableIt>::value_type query_sparse_table(TableIt st, size_t n, size_t l, size_t r, const Op& op = {}) {
    assert(l <= r && r < n);
    r++;
    const size_t h = details::bsr(r - l), ph = size_t(1) << h;
    const auto row = st + (n * h + h + 1 - ph);
    return op(row[l], row[r - ph]);
}

template<typename It, typename Op>
class SparseTableView {
public:
    using value_type = typename std::iterator_traits<It>::value_type;
    using size_type = unsigned;
    using operator_type = Op;

protected:
    It st;
    size_type n;
    NO_UNIQUE_ADDRESS operator_type op;

public:
    SparseTableView(It it, size_type n, const operator_type& op = {}) : st(std::move(it)), n(n), op(op) {}

    inline size_type size() const noexcept {
        return n;
    }

    // 闭区间
    inline value_type query(size_type l, size_type r) const {
        return query_sparse_table(st, n, l, r, op);
    }
    // 闭区间
    inline value_type query(size_type l, size_type r, const value_type& unitary) const {
        return r <= l ? unitary : query(l, r);
    }
};

template<typename T, typename Op>
class SparseTable : protected SparseTableView<T*, Op> {
private:
    using base_type = SparseTableView<T*, Op>;

public:
    using typename base_type::value_type;
    using typename base_type::size_type;
    using typename base_type::operator_type;
    using pointer = value_type*;
    using reference = value_type&;
    using const_pointer = const value_type*;
    using const_reference = const value_type&;

private:
    using allocator_type = std::allocator<value_type>;
    using allocator_traits = std::allocator_traits<allocator_type>;

    inline const operator_type& operator_() const noexcept {
        return this->op;
    }

    inline static allocator_type& allocator() noexcept {
        static allocator_type alloc{};
        return alloc;
    }

    struct Guard {
        pointer ptr;
        size_type len;
        ~Guard() { if (len > 0) allocator_traits::deallocate(allocator(), ptr, len); }
    };

    inline void clean() noexcept {
        if (this->n > 0) {
            const size_type st_size = sparse_table_size(this->n);
            if (!std::is_trivially_destructible<value_type>::value) {
                const pointer end = this->st + st_size;
                for (pointer it = this->st;it != end;++it)
                    allocator_traits::destroy(allocator(), it);
            }
            allocator_traits::deallocate(allocator(), this->st, st_size);
        }
    }

public:
    template<typename It>
    SparseTable(It it, size_type n, const Op& op = {})
            : base_type(nullptr, n, op)
    {
        if (n == 0) return;
        const size_type st_size = sparse_table_size(n);
        Guard guard = {allocator_traits::allocate(allocator(), st_size), st_size};
        details::InitializerIterator<allocator_type> initializer(guard.ptr, allocator());
        for (size_type i = 0;i < n;++i, ++it)
            *initializer++ = *it;
        make_sparse_table(guard.ptr, n, std::move(initializer), operator_()).release();
        this->st = guard.ptr;
        guard.len = 0;
    }

    template<typename S>
    SparseTable(const S& seq, const Op& op = {}) : SparseTable(seq.begin(), seq.size(), op) {}

    SparseTable(const SparseTable&) = delete;

    SparseTable(SparseTable&& other) noexcept
            : base_type(std::move(other))
    {
        other.st = nullptr;
        other.n = 0;
    }

    SparseTable& operator=(const SparseTable&) = delete;

    SparseTable& operator=(SparseTable&& other) noexcept {
        clean();
        base_type::operator=(std::move(other));
        other.st = nullptr;
        other.n = 0;
        return *this;
    }

    ~SparseTable() {
        clean();
    }

    inline void clear() noexcept {
        clean();
        this->st = nullptr;
        this->n = 0;
    }

    inline SparseTableView<const_pointer, Op> view() const {
        return SparseTableView<const_pointer, Op>(this->st, this->n, this->op);
    }

    using base_type::size;
    using base_type::query;
};

class Solution {
public:
    struct MAX {
        int operator()(int x, int y) const noexcept {
            return std::max(x, y);
        }
    };

    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        SparseTable<int, MAX> st(nums);
        vector<int> ans;
        for (size_t i = 0, n = nums.size(); i + k <= n; ++i)
            ans.push_back(st.query(i, i + k - 1)); // 调整为闭区间
        return ans;
    }
};

template<typename T>
struct MAX {
    T operator()(T x, T y) const noexcept {
        return std::max(x, y);
    }
};

template<typename T>
struct MIN {
    T operator()(T x, T y) const noexcept {
        return std::min(x, y);
    }
};

template<typename T>
struct SUM {
    T operator()(T x, T y) const noexcept {
        return x + y;
    }
};

struct MaxIndex {
    const vector<int>& nums;
    MaxIndex(const vector<int>& nums) : nums(nums) {}
    int operator()(int i, int j) const noexcept {
        return nums[i] >= nums[j] ? i : j;
    }
};

struct MinIndex {
    const vector<int>& nums;
    MinIndex(const vector<int>& nums) : nums(nums) {}
    int operator()(int i, int j) const noexcept {
        return nums[i] <= nums[j] ? i : j;
    }
};

template<typename T>
struct SparseTableMaxIndex {
    MaxIndex max_index;
    vector<int> indices;
    SparseTable<T, MaxIndex> max_st;
    SparseTableMaxIndex(const vector<int>& nums) : max_index(nums), indices(nums.size()),
        max_st((iota(indices.begin(), indices.end(), 0), indices), max_index) {}


        T query(int l, int r) const {
            return max_st.query(l, r);
        }
};

template<typename T>
struct SparseTableMinIndex {
    MinIndex min_index;
    vector<int> indices;
    SparseTable<T, MinIndex> min_st;
    SparseTableMinIndex(const vector<int>& nums) : min_index(nums), indices(nums.size()),
        min_st((iota(indices.begin(), indices.end(), 0), indices), min_index) {}

        T query(int l, int r) const {
            return min_st.query(l, r);
        }
};

template<typename T>
using SparseTableSum = SparseTable<T, SUM<T>>;

template<typename T>
using SparseTableMax = SparseTable<T, MAX<T>>;

template<typename T>
using SparseTableMin = SparseTable<T, MIN<T>>;


int main() {
    vector<int> nums = {1, -1, 4, 7};
    // 闭区间查询
    SparseTableMaxIndex<int> st(nums);
    for (int i = 0; i < 4; i++) {
        for (int j = i; j <= 4; j++) {
            cout << st.query(i, j) << " "; // 调整为闭区间
        }
        cout << endl;
    }
}

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

#ifndef NO_UNIQUE_ADDRESS
#    ifdef __has_cpp_attribute
#        if __has_cpp_attribute(no_unique_address)
#            define NO_UNIQUE_ADDRESS [[no_unique_address]]
#        endif
#    endif
#    ifndef NO_UNIQUE_ADDRESS
#        define NO_UNIQUE_ADDRESS
#    endif
#endif // !NO_UNIQUE_ADDRESS

namespace details {
    inline unsigned int bsf32(uint32_t n) noexcept {
#if defined __GNUC__
        return __builtin_ctz(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanForward(&ans, n);
        return ans;
#elif
        static constexpr unsigned char table[32] = {
            0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
            31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
        };
        return table[((n & -n) * 0x077CB531) >> 57];
#endif
    }

    inline unsigned int bsf64(uint64_t n) noexcept {
#if defined __GNUC__
        return __builtin_ctzll(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanForward64(&ans, n);
        return ans;
#elif
        static constexpr unsigned char table[64] = {
            0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
            62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
            63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
            54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
        };
        return table[((n & -n) * 0x03f79d71b4ca8b09) >> 58];
#endif
    }

    inline unsigned int bsr32(uint32_t n) noexcept {
#if defined __GNUC__
        return 31 - __builtin_clz(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanReverse(&ans, n);
        return ans;
#elif
        float t = n;
        uint32_t ans;
        memcpy(&ans, &t, sizeof(float));
        return (ans >> 23 & 255) - 127;
#endif
    }

    inline unsigned int bsr64(uint64_t n) noexcept {
#if defined __GNUC__
        return 63 - __builtin_clzll(n);
#elif defined _MSC_VER
        unsigned long ans;
        _BitScanReverse64(&ans, n);
        return ans;
#elif
        float t = n;
        uint32_t ans;
        memcpy(&ans, &t, sizeof(float));
        return (ans >> 23 & 255) - 127;
#endif
    }

    inline unsigned int popcnt32(uint32_t n) noexcept {
#if defined __GNUC__
        return __builtin_popcount(n);
#elif defined _MSC_VER
        return __popcnt(n);
#elif
        n -= ((n >> 1) & 0x55555555);
        n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
        return ((((n >> 4) + n) & 0x0f0f0f0f) * 0x01010101) >> 24;
#endif
    }

    inline unsigned int popcnt64(uint64_t n) noexcept {
#if defined __GNUC__
        return __builtin_popcountll(n);
#elif defined _MSC_VER
        return __popcnt64(n);
#elif
        n -= ((n >> 1) & 0x5555555555555555);
        n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333);
        return ((((n >> 4) + n) & 0x0f0f0f0f0f0f0f0f) * 0x0101010101010101) >> 56;
#endif
    }

    inline unsigned int parity32(uint32_t n) noexcept {
#if defined __GNUC__
        return __builtin_parity(n);
#elif defined _MSC_VER
        return __popcnt(n) & 1;
#elif
        n ^= n >> 1;
        n ^= n >> 2;
        n = (n & 0x11111111) * 0x11111111;
        return (n >> 28) & 1;
#endif
    }

    inline unsigned int parity64(uint64_t n) noexcept {
#if defined __GNUC__
        return __builtin_parityll(n);
#elif defined _MSC_VER
        return __popcnt64(n) & 1;
#elif
        n ^= n >> 1;
        n ^= n >> 2;
        n = (n & 0x1111111111111111) * 0x1111111111111111;
        return (n >> 60) & 1;
#endif
    }


    template<typename I, bool B = 32 < std::numeric_limits<I>::digits>
    struct _BitFuncImpl {
        inline static unsigned int bsf(I n) noexcept { return bsf64(n); }
        inline static unsigned int bsr(I n) noexcept { return bsr64(n); }
        inline static unsigned int popcnt(I n) noexcept { return popcnt64(n); }
        inline static unsigned int parity(I n) noexcept { return parity64(n); }
    };

    template<typename I>
    struct _BitFuncImpl<I, false> {
        inline static unsigned int bsf(I n) noexcept { return bsf32(n); }
        inline static unsigned int bsr(I n) noexcept { return bsr32(n); }
        inline static unsigned int popcnt(I n) noexcept { return popcnt32(n); }
        inline static unsigned int parity(I n) noexcept { return parity32(n); }
    };

    template<typename I>
    inline unsigned int bsf(I n) noexcept { return _BitFuncImpl<I>::bsf(n); }
    template<typename I>
    inline unsigned int bsr(I n) noexcept { return _BitFuncImpl<I>::bsr(n); }
    template<typename I>
    inline unsigned int popcnt(I n) noexcept { return _BitFuncImpl<I>::popcnt(n); }
    template<typename I>
    inline unsigned int parity(I n) noexcept { return _BitFuncImpl<I>::parity(n); }

    template<typename T, size_t K = 0, bool = std::is_empty<T>::value && !std::is_final<T>::value>
    struct Derivable {
    private:
        T val;
    public:
        constexpr Derivable() = default;
        template<typename... Args>
        constexpr Derivable(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value) : val(std::forward<Args>(args)...) {}
        inline constexpr T& value() noexcept { return val; }
        inline constexpr const T& value() const noexcept { return val; }
    };

    template<typename T, size_t K>
    struct Derivable<T, K, true> : private T {
        constexpr Derivable() = default;
        template<typename... Args>
        constexpr Derivable(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value) : T(std::forward<Args>(args)...) {}
        inline constexpr T& value() noexcept { return *this; }
        inline constexpr const T& value() const noexcept { return *this; }
    };

    template<typename Alloc>
    struct InitializerIterator {
        using traits = std::allocator_traits<Alloc>;
        using pointer = typename traits::pointer;
        using value_type = typename traits::value_type;
        InitializerIterator(const InitializerIterator&) = delete;
        InitializerIterator(InitializerIterator&& other) noexcept
                : ptr(other.ptr), cur(other.cur), p_alloc(other.p_alloc)
        {
            other.ptr = other.cur = nullptr;
            other.p_alloc = nullptr;
        }
        InitializerIterator(pointer ptr, Alloc& alloc) noexcept : ptr(ptr), cur(ptr), p_alloc(&alloc) {}
        ~InitializerIterator() noexcept {
            if (!std::is_trivially_destructible<value_type>::value)
                for (pointer it = ptr;it != cur;++it)
                    traits::destroy(*p_alloc, std::addressof(*it));
        }
        inline pointer release() noexcept {
            return ptr = cur;
        }
        inline InitializerIterator& operator*() noexcept { return *this; }
        inline InitializerIterator& operator++() noexcept { return *this; }
        inline InitializerIterator& operator++(int) noexcept { return *this;  }
        InitializerIterator& operator=(const InitializerIterator&) = delete;
        InitializerIterator& operator=(InitializerIterator&& other) noexcept {
            ptr = other.ptr;
            cur = other.cur;
            p_alloc = other.p_alloc;
            other.ptr = other.cur = nullptr;
            other.p_alloc = nullptr;
            return *this;
        }
        template<typename T>
        inline InitializerIterator& operator=(T&& val) noexcept(noexcept(std::is_nothrow_constructible<value_type, T&&>::value)) {
            traits::construct(*p_alloc, std::addressof(*cur), std::forward<T>(val));
            ++cur;
            return *this;
        }
    private:
        pointer ptr, cur;
        Alloc* p_alloc;
    };
}

template<typename TableIt, typename OutIt, typename Op>
inline OutIt make_sparse_table(TableIt st, size_t n, OutIt it, const Op& op = {}) {
    TableIt pre = std::move(st);
    for (size_t i = 2;i <= n;i *= 2) {
        for (size_t j = 0;j <= n - i;++j)
            *it++ = op(pre[j], pre[j + i / 2]);
        pre += n + 1 - i / 2;
    }
    return std::move(it);
}

inline size_t sparse_table_size(size_t n) {
    const size_t h = details::bsr(n) + size_t(1);
    return n * h + h + size_t(1) - (size_t(1) << h);
}

template<typename TableIt, typename Op>
inline typename std::iterator_traits<TableIt>::value_type query_sparse_table(TableIt st, size_t n, size_t l, size_t r, const Op& op = {}) {
    const size_t h = details::bsr(r - l), ph = size_t(1) << h;
    const auto row = st + (n * h + h + 1 - ph);
    return op(row[l], row[r - ph]);
}

template<typename It, typename Op>
class SparseTableView {
public:
    using value_type = typename std::iterator_traits<It>::value_type;
    using size_type = unsigned;
    using operator_type = Op;

protected:
    It st;
    size_type n;
    NO_UNIQUE_ADDRESS operator_type op;

public:
    SparseTableView(It it, size_type n, const operator_type& op = {}) : st(std::move(it)), n(n), op(op) {}

    inline size_type size() const noexcept {
        return n;
    }

    inline value_type query(size_type l, size_type r) const {
        return query_sparse_table(st, n, l, r, op);
    }

    inline value_type query(size_type l, size_type r, const value_type& unitary) const {
        return r <= l ? unitary : query(l, r);
    }
};

template<typename T, typename Op>
class SparseTable : protected SparseTableView<T*, Op> {
private:
    using base_type = SparseTableView<T*, Op>;

public:
    using typename base_type::value_type;
    using typename base_type::size_type;
    using typename base_type::operator_type;
    using pointer = value_type*;
    using reference = value_type&;
    using const_pointer = const value_type*;
    using const_reference = const value_type&;

private:
    using allocator_type = std::allocator<value_type>;
    using allocator_traits = std::allocator_traits<allocator_type>;

    inline const operator_type& operator_() const noexcept {
        return this->op;
    }

    inline static allocator_type& allocator() noexcept {
        static allocator_type alloc{};
        return alloc;
    }

    struct Guard {
        pointer ptr;
        size_type len;
        ~Guard() { if (len > 0) allocator_traits::deallocate(allocator(), ptr, len); }
    };

    inline void clean() noexcept {
        if (this->n > 0) {
            const size_type st_size = sparse_table_size(this->n);
            if (!std::is_trivially_destructible<value_type>::value) {
                const pointer end = this->st + st_size;
                for (pointer it = this->st;it != end;++it)
                    allocator_traits::destroy(allocator(), it);
            }
            allocator_traits::deallocate(allocator(), this->st, st_size);
        }
    }

public:
    template<typename It>
    SparseTable(It it, size_type n, const Op& op = {})
            : base_type(nullptr, n, op)
    {
        if (n == 0) return;
        const size_type st_size = sparse_table_size(n);
        Guard guard = {allocator_traits::allocate(allocator(), st_size), st_size};
        details::InitializerIterator<allocator_type> initializer(guard.ptr, allocator());
        for (size_type i = 0;i < n;++i, ++it)
            *initializer++ = *it;
        make_sparse_table(guard.ptr, n, std::move(initializer), operator_()).release();
        this->st = guard.ptr;
        guard.len = 0;
    }

    template<typename S>
    SparseTable(const S& seq, const Op& op = {}) : SparseTable(seq.begin(), seq.size(), op) {}

    SparseTable(const SparseTable&) = delete;

    SparseTable(SparseTable&& other) noexcept
            : base_type(std::move(other))
    {
        other.st = nullptr;
        other.n = 0;
    }

    SparseTable& operator=(const SparseTable&) = delete;

    SparseTable& operator=(SparseTable&& other) noexcept {
        clean();
        base_type::operator=(std::move(other));
        other.st = nullptr;
        other.n = 0;
        return *this;
    }

    ~SparseTable() {
        clean();
    }

    inline void clear() noexcept {
        clean();
        this->st = nullptr;
        this->n = 0;
    }

    inline SparseTableView<const_pointer, Op> view() const {
        return SparseTableView<const_pointer, Op>(this->st, this->n, this->op);
    }

    using base_type::size;
    using base_type::query;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值