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: Dynamic Range Affine Range Sum (verify/data_structures/treap/dynamic_sequence_range_affine_range_sum.test.cpp)

Depends on

Code

// @brief Dynamic Range Affine Range Sum
#define PROBLEM "https://judge.yosupo.jp/problem/dynamic_sequence_range_affine_range_sum"
#include "cp-algo/math/modint.hpp"
#include "cp-algo/data_structures/treap/metas/reverse.hpp"
#include "cp-algo/data_structures/treap.hpp"
#include <bits/stdc++.h>

using namespace std;
using namespace cp_algo::data_structures::treap;

using base = cp_algo::math::modint<998244353>;
using meta = metas::reverse_meta<base>;
using node_t = node<meta>;
using treap = node_t::treap;

void solve() {
    istream_iterator<int> input(cin);
    int n = *input++;
    int q = *input++;
    vector<treap> nodes(n);
    generate_n(begin(nodes), n, [&](){
        return node_t::make_treap(meta(*input++));
    });
    auto me = node_t::build(nodes);

    while(q--) {
        int t = *input++;
        if(t == 0) {
            int i = *input++;
            base x = *input++;
            node_t::insert(me, i, node_t::make_treap(meta(x)));
        } else if(t == 1) {
            node_t::erase(me, *input++);
        } else if(t == 2) {
            int l = *input++;
            int r = *input++;
            node_t::exec_on_segment(me, l, r, [](auto &t) {
                _safe_meta(t, reverse = 1);
            });
        } else if(t == 3) {
            int l = *input++;
            int r = *input++;
            base b = *input++;
            base c = *input++;
            node_t::exec_on_segment(me, l, r, [b, c](auto &t) {
                _safe_meta(t, add_push(meta::lin(b, c)));
            });
        } else {
            int l = *input++;
            int r = *input++;
            node_t::exec_on_segment(me, l, r, [](auto t) {
                cout << _safe_meta(t, sum) << "\n";
            });
        }
    }
}

signed main() {
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t = 1;
    while(t--) {
        solve();
    }
}
#line 1 "verify/data_structures/treap/dynamic_sequence_range_affine_range_sum.test.cpp"
// @brief Dynamic Range Affine Range Sum
#define PROBLEM "https://judge.yosupo.jp/problem/dynamic_sequence_range_affine_range_sum"
#line 1 "cp-algo/math/modint.hpp"


#line 1 "cp-algo/math/common.hpp"


#include <functional>
#include <cstdint>
namespace cp_algo::math {
#ifdef CP_ALGO_MAXN
    const int maxn = CP_ALGO_MAXN;
#else
    const int maxn = 1 << 19;
#endif
    const int magic = 64; // threshold for sizes to run the naive algo

    auto bpow(auto const& x, int64_t n, auto const& one, auto op) {
        if(n == 0) {
            return one;
        } else {
            auto t = bpow(x, n / 2, one, op);
            t = op(t, t);
            if(n % 2) {
                t = op(t, x);
            }
            return t;
        }
    }
    auto bpow(auto x, int64_t n, auto ans) {
        return bpow(x, n, ans, std::multiplies{});
    }
    template<typename T>
    T bpow(T const& x, int64_t n) {
        return bpow(x, n, T(1));
    }
}

#line 4 "cp-algo/math/modint.hpp"
#include <iostream>
namespace cp_algo::math {
    template<typename modint>
    struct modint_base {
        static int64_t mod() {
            return modint::mod();
        }
        modint_base(): r(0) {}
        modint_base(int64_t rr): r(rr % mod()) {
            r = std::min(r, r + mod());
        }
        modint inv() const {
            return bpow(to_modint(), mod() - 2);
        }
        modint operator - () const {return std::min(-r, mod() - r);}
        modint& operator /= (const modint &t) {
            return to_modint() *= t.inv();
        }
        modint& operator *= (const modint &t) {
            if(mod() <= uint32_t(-1)) {
                r = r * t.r % mod();
            } else {
                r = __int128(r) * t.r % mod();
            }
            return to_modint();
        }
        modint& operator += (const modint &t) {
            r += t.r; r = std::min(r, r - mod());
            return to_modint();
        }
        modint& operator -= (const modint &t) {
            r -= t.r; r = std::min(r, r + mod());
            return to_modint();
        }
        modint operator + (const modint &t) const {return modint(to_modint()) += t;}
        modint operator - (const modint &t) const {return modint(to_modint()) -= t;}
        modint operator * (const modint &t) const {return modint(to_modint()) *= t;}
        modint operator / (const modint &t) const {return modint(to_modint()) /= t;}
        auto operator <=> (const modint_base &t) const = default;
        int64_t rem() const {return 2 * r > (uint64_t)mod() ? r - mod() : r;}

        // Only use if you really know what you're doing!
        uint64_t modmod() const {return 8ULL * mod() * mod();};
        void add_unsafe(uint64_t t) {r += t;}
        void pseudonormalize() {r = std::min(r, r - modmod());}
        modint const& normalize() {
            if(r >= (uint64_t)mod()) {
                r %= mod();
            }
            return to_modint();
        }
        uint64_t& setr() {return r;}
        uint64_t getr() const {return r;}
    private:
        uint64_t r;
        modint& to_modint() {return static_cast<modint&>(*this);}
        modint const& to_modint() const {return static_cast<modint const&>(*this);}
    };
    template<typename modint>
    std::istream& operator >> (std::istream &in, modint_base<modint> &x) {
        return in >> x.setr();
    }
    template<typename modint>
    std::ostream& operator << (std::ostream &out, modint_base<modint> const& x) {
        return out << x.getr();
    }

    template<typename modint>
    concept modint_type = std::is_base_of_v<modint_base<modint>, modint>;

    template<int64_t m>
    struct modint: modint_base<modint<m>> {
        static constexpr int64_t mod() {return m;}
        using Base = modint_base<modint<m>>;
        using Base::Base;
    };

    struct dynamic_modint: modint_base<dynamic_modint> {
        static int64_t mod() {return m;}
        static void switch_mod(int64_t nm) {m = nm;}
        using Base = modint_base<dynamic_modint>;
        using Base::Base;

        // Wrapper for temp switching
        auto static with_mod(int64_t tmp, auto callback) {
            struct scoped {
                int64_t prev = mod();
                ~scoped() {switch_mod(prev);}
            } _;
            switch_mod(tmp);
            return callback();
        }
    private:
        static int64_t m;
    };
    int64_t dynamic_modint::m = 0;
}

#line 1 "cp-algo/data_structures/treap/metas/reverse.hpp"


#line 1 "cp-algo/data_structures/treap/metas/base.hpp"


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


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

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

#line 1 "cp-algo/math/affine.hpp"


#include <optional>
#include <utility>
#include <cassert>
#include <tuple>
namespace cp_algo::math {
    // a * x + b
    template<typename base>
    struct lin {
        base a = 1, b = 0;
        std::optional<base> c;
        lin() {}
        lin(base b): a(0), b(b) {}
        lin(base a, base b): a(a), b(b) {}
        lin(base a, base b, base _c): a(a), b(b), c(_c) {}

        // polynomial product modulo x^2 - c
        lin operator * (const lin& t) {
            assert(c && t.c && *c == *t.c);
            return {a * t.b + b * t.a, b * t.b + a * t.a * (*c), *c};
        }

        // a * (t.a * x + t.b) + b
        lin apply(lin const& t) const {
            return {a * t.a, a * t.b + b};
        }

        void prepend(lin const& t) {
            *this = t.apply(*this);
        }

        base eval(base x) const {
            return a * x + b;
        }
    };

    // (ax+b) / (cx+d)
    template<typename base>
    struct linfrac {
        base a, b, c, d;
        linfrac(): a(1), b(0), c(0), d(1) {} // x, identity for composition
        linfrac(base a): a(a), b(1), c(1), d(0) {} // a + 1/x, for continued fractions
        linfrac(base a, base b, base c, base d): a(a), b(b), c(c), d(d) {}

        // composition of two linfracs
        linfrac operator * (linfrac t) const {
            return t.prepend(linfrac(*this));
        }

        linfrac operator-() const {
            return {-a, -b, -c, -d};
        }

        linfrac adj() const {
            return {d, -b, -c, a};
        }
        
        linfrac& prepend(linfrac const& t) {
            t.apply(a, c);
            t.apply(b, d);
            return *this;
        }

        // apply linfrac to A/B
        void apply(base &A, base &B) const {
            std::tie(A, B) = std::pair{a * A + b * B, c * A + d * B};
        }
    };
}

#line 6 "cp-algo/data_structures/treap/metas/reverse.hpp"
namespace cp_algo::data_structures::treap::metas {
        template<typename base>
        struct reverse_meta: base_meta {
            using lin = math::lin<base>;
            base val;
            size_t sz = 1;
            bool reverse = false;
            base sum = val;
            
            lin to_push = {};

            reverse_meta(base val): val(val) {}

            void pull(auto const L, auto const R) {
                sum = val + _safe_meta(L, sum) + _safe_meta(R, sum);
                sz = 1 + _safe_meta(L, sz) + _safe_meta(R, sz);
            }
            void add_push(lin const& t) {
                val = t.eval(val);
                sum = t.a * sum + t.b * sz;
                to_push.prepend(t);
            }
            void push(auto &L, auto &R) {
                if(reverse) {
                    reverse = false;
                    std::swap(L, R);
                    _safe_meta(L, reverse ^= 1);
                    _safe_meta(R, reverse ^= 1);
                }
                if(to_push.a != 1 || to_push.b != 0) {
                    _safe_meta(L, add_push(to_push));
                    _safe_meta(R, add_push(to_push));
                    to_push = {};
                }
            }
        };
}

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


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


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

#line 5 "cp-algo/data_structures/treap.hpp"
#include <array>
namespace cp_algo::data_structures::treap {
    template<typename meta>
    struct node {
        using treap = node*;
        meta _meta;
        int prior = 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) {
            std::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 6 "verify/data_structures/treap/dynamic_sequence_range_affine_range_sum.test.cpp"
#include <bits/stdc++.h>

using namespace std;
using namespace cp_algo::data_structures::treap;

using base = cp_algo::math::modint<998244353>;
using meta = metas::reverse_meta<base>;
using node_t = node<meta>;
using treap = node_t::treap;

void solve() {
    istream_iterator<int> input(cin);
    int n = *input++;
    int q = *input++;
    vector<treap> nodes(n);
    generate_n(begin(nodes), n, [&](){
        return node_t::make_treap(meta(*input++));
    });
    auto me = node_t::build(nodes);

    while(q--) {
        int t = *input++;
        if(t == 0) {
            int i = *input++;
            base x = *input++;
            node_t::insert(me, i, node_t::make_treap(meta(x)));
        } else if(t == 1) {
            node_t::erase(me, *input++);
        } else if(t == 2) {
            int l = *input++;
            int r = *input++;
            node_t::exec_on_segment(me, l, r, [](auto &t) {
                _safe_meta(t, reverse = 1);
            });
        } else if(t == 3) {
            int l = *input++;
            int r = *input++;
            base b = *input++;
            base c = *input++;
            node_t::exec_on_segment(me, l, r, [b, c](auto &t) {
                _safe_meta(t, add_push(meta::lin(b, c)));
            });
        } else {
            int l = *input++;
            int r = *input++;
            node_t::exec_on_segment(me, l, r, [](auto t) {
                cout << _safe_meta(t, sum) << "\n";
            });
        }
    }
}

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++ example_00 :heavy_check_mark: AC 6 ms 3 MB
g++ extreme_insertion_00 :heavy_check_mark: AC 178 ms 58 MB
g++ extreme_insertion_01 :heavy_check_mark: AC 221 ms 58 MB
g++ extreme_insertion_02 :heavy_check_mark: AC 208 ms 58 MB
g++ max_00 :heavy_check_mark: AC 1185 ms 117 MB
g++ max_01 :heavy_check_mark: AC 814 ms 62 MB
g++ max_02 :heavy_check_mark: AC 1740 ms 62 MB
g++ max_03 :heavy_check_mark: AC 1877 ms 62 MB
g++ max_04 :heavy_check_mark: AC 1528 ms 62 MB
g++ random_00 :heavy_check_mark: AC 1139 ms 49 MB
g++ random_01 :heavy_check_mark: AC 1197 ms 58 MB
g++ random_02 :heavy_check_mark: AC 538 ms 10 MB
g++ random_03 :heavy_check_mark: AC 152 ms 54 MB
g++ random_04 :heavy_check_mark: AC 292 ms 36 MB
g++ small_00 :heavy_check_mark: AC 7 ms 4 MB
g++ small_01 :heavy_check_mark: AC 7 ms 3 MB
g++ small_02 :heavy_check_mark: AC 7 ms 3 MB
g++ small_03 :heavy_check_mark: AC 7 ms 4 MB
g++ small_04 :heavy_check_mark: AC 7 ms 4 MB
g++ small_05 :heavy_check_mark: AC 7 ms 4 MB
g++ small_06 :heavy_check_mark: AC 7 ms 4 MB
g++ small_07 :heavy_check_mark: AC 7 ms 4 MB
g++ small_08 :heavy_check_mark: AC 7 ms 4 MB
g++ small_09 :heavy_check_mark: AC 6 ms 3 MB
g++ wrong_avl_killer_00 :heavy_check_mark: AC 238 ms 58 MB
g++ wrong_avl_killer_01 :heavy_check_mark: AC 229 ms 58 MB
Back to top page