/// An optimized version of persistent treap with allocator. Gets AC in problem F in ~1.5s. /// See treap8_persistency.cpp for the story behind the bug. #include using namespace std; using ll = long long; using ull = unsigned long long; mt19937 mt(736); template class chunk_alloc { public: static constexpr auto chunk_size = sz; private: using chunk_t = array; deque mem; stack emp; public: void *allocate() { if (emp.empty()) emp.push(reinterpret_cast(&mem.emplace_back())); auto ans = emp.top(); emp.pop(); return ans; } void deallocate(void *p) noexcept { emp.push(p); } }; chunk_alloc<64> pool; // 64 is the magic number template struct dummy_alloc { using value_type = T; dummy_alloc() noexcept = default; template explicit dummy_alloc(const dummy_alloc &) noexcept {} T *allocate(std::size_t n) { // cerr << sizeof(value_type) << endl; // the only way to get the magic number if constexpr (sizeof(value_type) == decltype(pool)::chunk_size) return static_cast(pool.allocate()); else return static_cast(::operator new(n * sizeof(value_type))); } void deallocate(T *p, std::size_t n) { if constexpr (sizeof(value_type) == decltype(pool)::chunk_size) return pool.deallocate(p); else ::delete (p); } }; template constexpr bool operator==(const dummy_alloc &, const dummy_alloc &) noexcept { return true; } template constexpr bool operator!=(const dummy_alloc &, const dummy_alloc &) noexcept { return false; } template class treap { struct node { using nodeptr = shared_ptr; T x; nodeptr l, r; size_t sz; explicit node(T x = T{}) : x(x), l(nullptr), r(nullptr), sz(1) {} explicit node(T x, const nodeptr &l, const nodeptr &r) : x(x), l(l), r(r), sz(size(l) + 1 + size(r)) {} }; using nodeptr = typename node::nodeptr; template static nodeptr make_node(Args &&...x) { return allocate_shared(dummy_alloc{}, std::forward(x) ...); } static auto size(const nodeptr &h) { return h == nullptr ? 0 : h->sz; } static nodeptr merge(const nodeptr &le, const nodeptr &ri) { if (le == nullptr) return ri; if (ri == nullptr) return le; if (uniform_int_distribution{0, size(le) + size(ri) - 1}(mt) < size(le)) { auto rch = merge(le->r, ri); return make_node(le->x, le->l, rch); } else { auto lch = merge(le, ri->l); return make_node(ri->x, lch, ri->r); } } static pair split(const nodeptr &h, auto &&fn) // C++20 { if (h == nullptr) return {nullptr, nullptr}; if (fn(h)) { auto [le, ri] = split(h->r, std::forward(fn)); // structured binding, C++17 return {make_node(h->x, h->l, le), std::move(ri)}; } else { auto [le, ri] = split((h->l), std::forward(fn)); return {std::move(le), make_node(h->x, ri, h->r)}; } } static auto split_by_size(const nodeptr &h, size_t k) { return split(h, [&k](const nodeptr &h) { if (auto ind = size(h->l); ind < k) { k -= ind + 1; return true; } else return false; }); } nodeptr root = nullptr; template static nodeptr build(It be, It en) // builds a perfectly balanced tree { if (be == en) return nullptr; auto t = be + distance(be, en) / 2; return make_node(*t, build(be, t), build(t + 1, en)); } static void output(const nodeptr &h, auto it) { if (h == nullptr) return; output(h->l, it); *(it++) = h->x; output(h->r, it); } public: treap() = default; template treap(It be, It en) : root(build(be, en)) {} void rotate(size_t l, size_t m, size_t r) { auto [mi, ri] = split_by_size(std::move(root), r); auto [tmp, mi_r] = split_by_size(std::move(mi), m); auto [le, mi_l] = split_by_size(std::move(tmp), l); root = merge(merge(std::move(le), std::move(mi_r)), merge(std::move(mi_l), std::move(ri))); } void output(auto it) { output(root, it); } [[nodiscard]] auto size() const { return size(root); } T &operator[](size_t k) { auto [le, tmp] = split_by_size(root, k); auto [mi, ri] = split_by_size(std::move(tmp), 1); assert(mi != nullptr); auto &ans = mi->x; return ans; } }; void solve(istream &cin = std::cin, ostream &cout = std::cout) { int n, q; cin >> n >> q; vector ord(n); iota(ord.begin(), ord.end(), 1); treap tr(ord.begin(), ord.end()); for (int i = 0; i < q; i++) { int l, r; cin >> l >> r; l--; tr.rotate(0, l, r); } tr.output(ostream_iterator(cout, " ")); cout << endl; } void stress(istream &cin = std::cin, ostream &cout = std::cout) { int n, q; cin >> n >> q; vector ord(n); iota(ord.begin(), ord.end(), 1); for (int i = 0; i < q; i++) { int l, r; cin >> l >> r; l--; rotate(ord.begin(), ord.begin() + l, ord.begin() + r); } ranges::copy(ord, ostream_iterator(cout, " ")); cout << endl; } void gen(ostream &cout = std::cout) { const int n = 20, q = 10; cout << n << ' ' << q << endl; uniform_int_distribution uid(1, n); for (int i = 0; i < q; i++) { int l = uid(mt), r = uid(mt); if (r < l) swap(l, r); cout << l << ' ' << r << endl; } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout << fixed; #ifdef LOCAL auto st = chrono::steady_clock::now(); ifstream fin("../input.txt"); do { solve(fin); cout << "===" << endl; string str; while (getline(fin, str) && str != string(max(1, (int) str.size()), '=')); } while (fin); #ifdef STRESS for (int cnt = 1;; cnt++) { stringstream ss, in1, out1, in2, out2; gen(ss); in1 << ss.str(); in2 << ss.str(); solve(in1, out1); stress(in2, out2); if (out1.str() != out2.str()) { cout << "fail: " << cnt << endl; cout << ss.str(); cout << "solve:" << endl; cout << out1.str(); cout << "stress:" << endl; cout << out2.str(); break; } else if (cnt % 100 == 0) cout << "ok: " << cnt << endl; } #endif cout << setprecision((int) floor(log10(chrono::steady_clock::duration::period::den))); cout << "clock: " << chrono::duration(chrono::steady_clock::now() - st).count() << endl; #else solve(); #endif return 0; }