Algorithm/BOJ
[백준 1655] 가운데를 말해요
giiro
2020. 9. 6. 21:43
문제
1655번: 가운데를 말해요
첫째 줄에는 수빈이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 수빈이가 외치는 정수가 차례대로 주어진다. 정수는 -1
www.acmicpc.net
문제 풀이
1. 항상 중앙 값을 구하기 위해 우선순위 큐 두 개를 아래의 그림과 같이 사용해서 입력받는 수를 관리하기로 한다.
-
lpq = top쪽으로 갈수록 수가 커지는 max heap
-
rpq = top쪽으로 갈수론 수가 작아지는 min heap
2. 입력받는 수(k)는 항상 두 힙중 하나에 들어가야하며 중앙값을 구하기위해 두 힙의 크기는 항상 같거나 lpq가 rpq보다 크기가 1큰 경우만 만족할 수 있도록 수가 들어올때마다 적절히 힙을 조절한다.
-
수가 처음 들어올 때 : lpq에 저장
-
$lpq.size() >= rpq.size()$ 일 때 : rpq.top()와 k의 대소비교를 통해 어느 힙에 넣을지 정해주고 두 힙의 크기조정
-
$lpq.size() < rpq.size()$ 일 때 : 두 힙의 크기가 같을 때 k가 들어온 경우 항상 lpq의 크기가 크도록 조정했으므로 나올수 없음.
3. 지금까지 들어온 수의 개수가 홀수이면 lpq.top을, 짝수면 (lpq,rpq).top중 작은 것을 중앙값으로 저장
코드
#include <bits/stdc++.h>
using namespace std;
int n, k, temp;
priority_queue<int, vector<int>> lpq;
priority_queue<int, vector<int>, greater<>> rpq;
vector<int> ans;
int main() {
cin.tie(NULL); cout.tie(NULL);
ios_base::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> k;
if (i == 1) lpq.push(k);
else {
if (lpq.size() == rpq.size()) {
temp = rpq.top();
if (temp <= k) rpq.pop(), lpq.push(temp), rpq.push(k);
else lpq.push(k);
}
else if (lpq.size() > rpq.size()) {
temp = lpq.top();
if (temp >= k) lpq.pop(), rpq.push(temp), lpq.push(k);
else rpq.push(k);
}
}
if (i % 2) ans.push_back(lpq.top());
else ans.push_back(min(lpq.top(), rpq.top()));
}
for (int i : ans) cout << i << " ";
}