출처 : www.acmicpc.net/problem/7662
문제
이중 우선순위 큐(dual priority queue)는 전형적인 우선순위 큐처럼 데이터를 삽입, 삭제할 수 있는 자료 구조이다.
전형적인 큐와의 차이점은 데이터를 삭제할 때 연산(operation) 명령에 따라 우선순위가 가장 높은 데이터 또는 가장 낮은 데이터 중 하나를 삭제하는 점이다.
이중 우선순위 큐를 위해선 두 가지 연산이 사용되는데, 하나는 데이터를 삽입하는 연산이고 다른 하나는 데이터를 삭제하는 연산이다. 데이터를 삭제하는 연산은 또 두 가지로 구분되는데 하나는 우선순위가 가장 높은 것을 삭제하기 위한 것이고 다른 하나는 우선순위가 가장 낮은 것을 삭제하기 위한 것이다.
주어진 정수 값 자체를 우선순위라고 했을 때, 주어진 명령이 모두 수행된 후 최솟값과 최댓값, 또는 비어있을 경우 "EMPTY"를 출력하는 문제
풀이
우선 문제를 읽으면서 생각나는건, 최대 힙과 최소 힙을 둘 다 만들어 두어야 한다는 점이다.
문제에선 "이중 우선 순위 큐"라고 하지만, 사실 우선순위가 가장 높은 데이터와 가장 낮은 데이터 둘 다 O(1) 만에 삭제하는 자료구조를 직접 구현할 방법은 없다. (아마도?)
따라서 우리는 최대 힙, 최소 힙을 둘 다 만들어 두고 이를 적용시켜야 하는데, 다만 문제 되는 부분은
만약 우선순위가 가장 높은 데이터를 삭제했을 경우 (최대 힙에서 pop을 한 경우)
최소 힙에는 아직 이 데이터가 남아 있다는 점이다.
이 부분은 "어떤 연산을 하더라도 두 힙의 원소의 개수, 종류가 다를 수 없다는 점"에서 착안해
따로 전체 배열에서 특정 원소가 몇 개 있는지를 기록해두고, 삽입, 삭제가 나왔을 때 +1, -1 처리해준 다음
나중에 삭제 시, 배열에 지금 없을 경우(다른 힙에서 삭제된 경우) 그냥 pop 하고, 다음 원소를 삭제하면 된다.
그리고 마지막에 원소를 출력 할 때도, 이 과정을 한 번 거쳐야 정확히 힙에 있는 원소를 출력할 수 있게 된다.
유의할 점은 문제에서 입력되는 정수가 32비트이기 때문에 정수 배열이 아닌, map을 이용해 기록해둬야 메모리 초과를 막을 수 있다. 이 부분은 명령 개수가 작기 때문에 할 수 있는 방법이다.
위 과정은 아래 코드 한 줄로 요약되니 참고하자. (최대 힙의 경우)
while (!max_pq.empty() && mp[max_pq.top()] == 0) max_pq.pop();
소스 코드(.cpp)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0);
int t; cin >> t;
while (t--) {
priority_queue<int, vector<int> >max_pq; // 최대 힙
priority_queue<int, vector<int>, greater<int> >min_pq; // 최소 힙
map<int, int>mp;
int k; cin >> k;
for (int i = 0; i < k; i++) {
char cmd; cin >> cmd;
if (cmd == 'I') {
int n; cin >> n;
max_pq.push(n);
min_pq.push(n);
mp[n]++;
}
else {
int n; cin >> n;
if (n == 1) {
while (!max_pq.empty() && mp[max_pq.top()] == 0) max_pq.pop();
if (max_pq.empty()) continue;
else {
int x = max_pq.top();
max_pq.pop();
mp[x]--;
}
}
else {
while (!min_pq.empty() && mp[min_pq.top()] == 0) min_pq.pop();
if (min_pq.empty()) continue;
else {
int x = min_pq.top();
min_pq.pop();
mp[x]--;
}
}
}
while (!max_pq.empty() && mp[max_pq.top()] == 0) max_pq.pop();
while (!min_pq.empty() && mp[min_pq.top()] == 0) min_pq.pop();
}
if (max_pq.empty()) cout << "EMPTY\n";
else {
cout << max_pq.top() << " " << min_pq.top() << "\n";
}
}
return 0;
}
'Koala - 2기' 카테고리의 다른 글
백준 13975 파일 합치기 3 (0) | 2021.02.18 |
---|---|
백준 1477 휴게소 세우기 (0) | 2021.02.16 |
[스택] 정올 1015번 브라우저 (0) | 2021.02.05 |
[1912번] 연속합 (0) | 2021.01.19 |
[모의 테스트 풀이] 랜선 자르기 & 수 찾기 (0) | 2021.01.10 |