F - Understory Editorial by en_translator
Overview of Problem
This problem is an exercise of a data structure called Priority Queue (Heap). This is implemented as heapq in Python, or priority_queue in C++.
Notes: Max- and Min- Heap
heapq in Python is a min-heap, which maintains the “minimum value” by default; meanwhile, priority_queue in C++ is a max-heap, which maintains the “maximum value” by default.
Thus, when we want to take out smaller values first in C++ (as in this problem), we need the following type arguments on declaration:
priority_queue<int, vector<int>, greater<int>> que;
What Heap Can Do
While detailed methods and complexity vary depending on implementation, a heap roughly supports the following operations. Let \(N\) be the number of elements in the heap when an operation is performed.
1. Retrieve the minimum value
- Retrieves the minimum value in the heap (without removing).
- Complexity: \(O(1)\)
- Python:
que[0] - C++:
que.top()
2. Take out the minimum value
- Removes the minimum value in the heap.
- Complexity: \(O(\log N)\)
- Python:
heappop(que) - C++:
que.pop()
3. Insert an element
- Inserts an element into the heap.
- Complexity \(O(\log N)\)
- Python :
heappush(que, x) - C++ :
que.push(x)
Implementation
In case of our problem, the problem can be solved by by implementing a simulation that performs:
Type \(1\)
Insert \(h\) to the heap.
Type \(2\)
Retrieve the minimum value, and remove it if it \(h\) or less. Repeat it until it is not \(h\) or less.
This can be implemented as follows:
Implementation in Python
from heapq import heappop, heappush
que = []
q = int(input())
for i in range(q):
t, h = map(int, input().split())
if t == 1:
heappush(que, h)
else:
while que and que[0] <= h:
heappop(que)
print(len(que))
Implementation in C++
#include <bits/stdc++.h>
using namespace std;
int main(){
int q; cin >> q;
priority_queue<int, vector<int>, greater<int>> que;
for(int i=0; i<q; i++){
int t, h; cin >> t >> h;
if (t == 1){
que.push(h);
}else{
while(!que.empty() and que.top() <= h){
que.pop();
}
}
cout << que.size() << endl;
}
}
Complexity
The complexity can be analyzed as follows.
Insertion
This occurs once per one type-\(1\) query, for a total of \(O(N)\) times.
Removal
One may feel that computational complexity may bloat up because we may remove many elements in a type-\(2\) query.
However, once an element is removed, it cannot be removed again, so “the number of removals” must be not greater than “the number of insertions.” Thus, it occurs a total of \(O(N)\) times.
Retrieval of minimum value
It is almost the same as the number of removals. In a type-\(2\) query, there may be an element that is referenced as the minimum value, but not removed.
However, such an element exists at most one per a query, so the number of occurrences is at most \(Q\) times more than the removal count. Thus, it is bounded by \(O(Q)\).
Hence, the complexity is \(O(Q \log Q)\).
posted:
last update: