C - Understory Editorial
by
harurun4635
問題の概要
この問題は「優先度付きキュー(ヒープ)」とよばれるデータ構造の練習問題です。例えば Python では heapq として、 C++ では priority_queue として、実装されています。
注意:最大・最小ヒープについて
Python の heapq はデフォルトで「最小値」を保持する最小ヒープ であるのに対して、 C++ の priority_queue はデフォルトで「最大値」を保持する最大ヒープとして動作します。
そのため、(今回の問題のように) C++ で最小値を優先して取り出すには、変数の宣言時に以下のように型引数を追加する必要があります。
priority_queue<int, vector<int>, greater<int>> que;
ヒープにできること
実装方針によって、細かなメソッド・計算量は異なりますが、およそ以下のような操作ができます。以下、操作時のヒープの要素数を \(N\) とします。
1. 最小値の取得
- (削除はせず)ヒープ内の最小値を取得します
- 計算量 \(O(1)\)
- Python :
que[0] - C++ :
que.top()
2. 最小値の取り出し
- ヒープ内の最小値を削除します
- 計算量 \(O(\log N)\)
- Python :
heappop(que) - C++ :
que.pop()
3. 要素の追加
- ヒープに要素を追加します
- 計算量 \(O(\log N)\)
- Python :
heappush(que, x) - C++ :
que.push(x)
実装
今回の問題であれば
タイプ \(1\)
ヒープに \(h\) を追加する。
タイプ \(2\)
最小値を取得し、それが \(h\) 以下なら削除する。\(h\) 以下でなくなるまで繰り返す。
というようなシミュレーションを書くことで、この問題に AC できます。以下のように実装できます。
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))
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;
}
}
計算量
計算量については以下のようになります。
挿入
タイプ \(1\) のクエリごとに \(1\) 回行います。よって全体で \(O(Q)\) 回です。
削除
タイプ \(2\) では \(1\) 回のクエリで、たくさんの要素を削除することもあり、計算量が大きくなると感じるかもしれません。
しかし、一度削除した要素は二度と削除できないことをかんがえると、「削除の回数」は「挿入の回数」以下となるはずです。よって全体で \(O(Q)\) 回です。
最小値の取得
ほとんど削除回数と同じです。タイプ \(2\) のクエリで、「最小値を確認したが、削除しない要素」が存在することがあります。
しかし、それは \(1\) クエリにつき高々 \(1\) つしか存在しないため、削除回数より高々 \(Q\) 回しか大きくなりません。よって全体で \(O(Q)\) 回です。
以上をまとめると、計算量は \(O(Q \log Q)\) となります。
posted:
last update:
