ソートの部分を速く済ませるのが課題. 毎回ソートするのではなく,必要な部分だけソートして, そうでないときはソートを保留しておきたい.
priority queue を用いると, 各元を追加したときに同時にソートされた形になる. 追加に \(O(log(size(que)))\) がかかる.
実装:
\(b\) を priority queue, \(a\) を queue とする. 組 \( (b,a) \) を,vector \(b * a\) と同一視する. ここで,\(b * a\) は \(b\) の元の後ろに \(a\) の元を並べた vector. もちろん,実装は ( (b,a) ) で行って,vector \(b*a\) は 実装には現れない.
とりあえず \(a\) の方に入れてソートを保留しておき, 必要な場面が来たときだけ \(b\) に入れてソートする.
出力クエリが来たら,\(b\) の先頭から取り出す. \(b\) が空のときは \(a\) の先頭から取り出す. 制約から,出力クエリのときに \(b,a\) のどちらかは空でない.
使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"
int main() {
ll q; cin >> q;
queue<ll> a;
min_priority_queue<ll> b;
// b*a
rep(qi,q){
ll t; cin >> t;
ll x;
if(t == 1){
cin >> x;
a.push(x);
}
else if(t == 2){
if(b.size()){
cout << b.top() << endl;
b.pop();
}else{
assert(a.size());
cout << a.front() << endl;
a.pop();
}
}else {
while(a.size()){
ll x = a.front(); a.pop();
b.push(x);
}
}
}
return 0;
}