|
1 | 1 | #pragma once |
2 | 2 | //! https://codeforces.com/blog/entry/111117 |
3 | 3 | //! @code |
4 | | -//! // DS = any struct with member functions join, undo |
5 | | -//! DS ds; |
6 | | -//! // int = argument type of DS::join |
7 | | -//! pq_updates<DS, int> pq(ds); |
8 | | -//! pq.push_update(val, pri); |
9 | | -//! pq.pop_update(); |
| 4 | +//! vector<pair<int, int>> updates; |
| 5 | +//! pq_updates pq([&](int update_id) {}, |
| 6 | +//! [&](int t) {}); |
| 7 | +//! updates.push_back({u, v}); |
| 8 | +//! pq.push(pri, ssize(updates) - 1); |
10 | 9 | //! @endcode |
11 | | -//! @time n interweaved calls to pop_update, push_update |
12 | | -//! take O(T(n)*nlogn) where O(T(n)) = time complexity of |
13 | | -//! DS::join and DS::undo |
14 | | -//! @space n interweaved calls to pop_update, push_update |
15 | | -//! uses O(n) space |
16 | | -template<class DS, class... ARGS> struct pq_updates { |
17 | | - DS ds; |
18 | | - using upd = |
19 | | - pair<tuple<ARGS...>, map<int, int>::iterator>; |
20 | | - vector<upd> upd_st; |
21 | | - map<int, int> |
22 | | - mp; //!< priority -> index into update stack |
23 | | - //! @param ds any data structure with member functions |
24 | | - //! `join` and `undo` |
25 | | - pq_updates(DS& ds): ds(ds) {} |
26 | | - //! Remove update with max priority |
27 | | - //! @time O(log(n) + k*T(n)) where k = # of pops off the |
28 | | - //! update stack |
29 | | - //! @space a temporary vector of size O(k) is used to |
30 | | - //! store popped updates; size of `upd_st`, `mp` member |
31 | | - //! variables decreases by 1 |
32 | | - void pop_update() { |
| 10 | +//! @time O(n log n) |
| 11 | +//! @space O(n) |
| 12 | +template<class F, class G> struct pq_updates { |
| 13 | + F update; |
| 14 | + G rollback; |
| 15 | + using upd = pair<multimap<int, int>::iterator, int>; |
| 16 | + vector<upd> st; |
| 17 | + multimap<int, int> mp; |
| 18 | + pq_updates(F update, G rollback): |
| 19 | + update(update), rollback(rollback) {} |
| 20 | + void pop() { |
33 | 21 | vector<upd> extra; |
34 | | - int idx = sz(upd_st) - 1, lowest_pri = INT_MAX; |
35 | | - for (auto it = rbegin(mp); |
36 | | - 2 * sz(extra) < sz(upd_st) - idx; it++) { |
37 | | - auto [pri, idx_sk] = *it; |
38 | | - extra.push_back(upd_st[idx_sk]); |
39 | | - idx = min(idx, idx_sk), lowest_pri = pri; |
| 22 | + int t = sz(st) - 1; |
| 23 | + for (auto it = rbegin(mp); 2 * sz(extra) < sz(st) - t; |
| 24 | + it++) { |
| 25 | + extra.push_back(st[it->second]); |
| 26 | + t = min(t, it->second); |
| 27 | + it->second = -1; |
40 | 28 | } |
41 | | - auto it = remove_if(idx + all(upd_st), [&](auto& cur) { |
42 | | - return cur.second->first >= lowest_pri; |
43 | | - }); |
44 | | - ranges::reverse_copy(extra, it); |
45 | | - rep(i, idx, sz(upd_st)) ds.undo(); |
46 | | - upd_st.pop_back(); |
47 | | - mp.erase(prev(end(mp))); |
48 | | - rep(i, idx, sz(upd_st)) { |
49 | | - apply(&DS::join, |
50 | | - tuple_cat(make_tuple(&ds), upd_st[i].first)); |
51 | | - upd_st[i].second->second = i; |
| 29 | + rollback(t); |
| 30 | + ranges::reverse_copy(extra, |
| 31 | + remove_if(t + all(st), |
| 32 | + [](upd& x) { return x.first->second == -1; })); |
| 33 | + st.pop_back(); |
| 34 | + mp.erase(extra[0].first); |
| 35 | + rep(i, t, sz(st)) { |
| 36 | + update(st[i].second); |
| 37 | + st[i].first->second = i; |
52 | 38 | } |
53 | 39 | } |
54 | | - //! @param args arguments to DS::join |
55 | | - //! @param pri must be distinct, can be negative |
56 | | - //! @time O(log(n) + T(n)) |
57 | | - //! @space an new update is allocated, inserted into |
58 | | - //! `upd_st`, `mp` member variables |
59 | | - void push_update(ARGS... args, int pri) { |
60 | | - ds.join(args...); |
61 | | - auto [it, ins] = mp.emplace(pri, sz(upd_st)); |
62 | | - assert(ins); |
63 | | - upd_st.emplace_back(make_tuple(args...), it); |
| 40 | + void push(int pri, int update_id) { |
| 41 | + update(update_id); |
| 42 | + st.emplace_back(mp.emplace(pri, sz(st)), update_id); |
64 | 43 | } |
65 | 44 | }; |
0 commit comments