Skip to content

Commit 82f513a

Browse files
committed
golf pq of updates
1 parent b9d7aed commit 82f513a

3 files changed

Lines changed: 97 additions & 62 deletions

File tree

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,44 @@
11
#pragma once
22
//! https://codeforces.com/blog/entry/111117
33
//! @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);
109
//! @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() {
3321
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;
4028
}
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;
5238
}
5339
}
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);
6443
}
6544
};

tests/library_checker_aizu_tests/data_structures/pq_ds_undo_sliding_window.test.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct stack_with_get_max {
1111
st.emplace_back(val,
1212
empty(st) ? val : min(val, st.back().second));
1313
}
14-
void undo() { st.pop_back(); }
14+
void rollback(int siz) { st.resize(siz); }
1515
int get_max() const { return st.back().second; }
1616
};
1717
int main() {
@@ -20,15 +20,21 @@ int main() {
2020
cin >> n >> l;
2121
vi arr(n);
2222
rep(i, 0, n) cin >> arr[i];
23+
vector<int> updates;
2324
stack_with_get_max stm;
24-
pq_updates<stack_with_get_max, int> pq(stm);
25+
pq_updates pq([&](int id) { stm.join(updates[id]); },
26+
[&](int t) { stm.rollback(t); });
2527
int pri = (n - l) / 2;
26-
rep(i, 0, l) pq.push_update(arr[i], pri--);
27-
cout << pq.ds.get_max();
28+
rep(i, 0, l) {
29+
updates.push_back(arr[i]);
30+
pq.push(pri--, updates.size() - 1);
31+
}
32+
cout << stm.get_max();
2833
rep(i, l, n) {
29-
pq.push_update(arr[i], pri--);
30-
pq.pop_update();
31-
cout << " " << pq.ds.get_max();
34+
updates.push_back(arr[i]);
35+
pq.push(pri--, updates.size() - 1);
36+
pq.pop();
37+
cout << " " << stm.get_max();
3238
}
3339
cout << '\n';
3440
return 0;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#define PROBLEM \
2+
"https://onlinejudge.u-aizu.ac.jp/problems/ITP1_1_A"
3+
#include "../template.hpp"
4+
#include "../../../library/contest/random.hpp"
5+
#include "../../../library/data_structures_[l,r)/uncommon/priority_queue_of_updates.hpp"
6+
int main() {
7+
for (int max_capacity = 1; max_capacity <= 50;
8+
max_capacity++) {
9+
rep(pattern, 0, 5) {
10+
vi ds_history;
11+
auto update = [&](int id) {
12+
ds_history.push_back(id);
13+
};
14+
auto rollback = [&](int t) { ds_history.resize(t); };
15+
pq_updates solver(update, rollback);
16+
map<pair<int, int>, int> naive_mp;
17+
int upd_id_counter = 0;
18+
rep(op, 0, 200) {
19+
bool do_push =
20+
naive_mp.empty() ||
21+
(rnd(0, 1) == 0 && sz(naive_mp) < max_capacity);
22+
if (do_push) {
23+
int upd_id = ++upd_id_counter;
24+
int pri;
25+
if (pattern == 0) pri = rnd(1, 5);
26+
else if (pattern == 1) pri = op / 5;
27+
else if (pattern == 2) pri = 10;
28+
else if (pattern == 3)
29+
pri = (op % 2 == 0) ? 1 : 2;
30+
else pri = rnd(1, 100);
31+
solver.push(pri, upd_id);
32+
naive_mp[{pri, upd_id}] = upd_id;
33+
} else {
34+
solver.pop();
35+
auto max_it = prev(end(naive_mp));
36+
naive_mp.erase(max_it);
37+
}
38+
vi active_ds = ds_history;
39+
sort(all(active_ds));
40+
vi active_naive;
41+
for (auto [key, id] : naive_mp)
42+
active_naive.push_back(id);
43+
sort(all(active_naive));
44+
assert(active_ds == active_naive);
45+
}
46+
}
47+
}
48+
cout << "Hello World\n";
49+
return 0;
50+
}

0 commit comments

Comments
 (0)