반응형
리뷰
https://www.acmicpc.net/problem/1572
https://www.acmicpc.net/problem/9426
처음엔 머지 소트 트리를 통해 접근하였으나 바로 시간 초과를 맞게 되었다.
이후 도는 0보다 크거나 같고, 65535보다 작거나 같은 정수라는 조건에 영감을 얻어 구간합 세그트리로 AC를 받았다.
1572번과 9426번 둘 다 같은 문제로 9426번은 레이팅 점수를 주지 않는다.
전역 변수
- N : n의 최대값을 저장할 정수형 상수 변수
- P : 온도의 최대값을 저장할 정수형 상수 변수
- n : 수열의 길이를 저장할 정수형 변수
- k : 부분 수열의 길이를 저장할 정수형 변수
- lst : 수열의 값을 저장할 정수형 배열
- tree : 세그먼트 트리 정보를 저장할 정수형 배열
함수
1. update
void update(int node, int s, int e, int idx, int val)
세그먼트 트리의 업데이트를 진행하기 위한 함수
- 매개변수로 노드 정보 node, 탐색 범위 s, e, 변경할 인덱스 idx, 변경할 값 val을 전달받는다.
- 기저 조건으로 리프 노드에 도달했을 경우 현재 노드에 val만큼 값을 더해준다.
- 리프 노드가 아닐 경우 정수형 변수 mid에 탐색 범위의 절반 값을 저장한다.
- idx가 mid보다 작거나 같을 경우 왼쪽 자식 노드로, 클 경우 오른쪽 자식 노드로 재귀를 진행한다.
- 재귀를 빠져나오며 현재 노드를 좌, 우 자식 노드 값의 합으로 저장하여 트리 상태를 업데이트 해준다.
2. query
int query(int node, int s, int e, int idx)
현재 부분 수열에서 중앙값을 찾아 리턴하기 위한 함수
- 기저조건으로 리프 노드에 도달하였다면 s, e 중 아무거나 리턴해 준다.
- 리프 노드가 아닐 경우 정수형 변수 mid에 탐색 범위의 절반 값을 저장한다.
- idx가 왼쪽 자식 노드의 값 보다 작거나 같을 경우 왼쪽으로 재귀를 진행해 준다.
- idx가 왼쪽 자식 노드의 값 보다 크다면 오른쪽으로 재귀를 진행해 준다.
문제풀이
- n, k값을 입력 받고, n개의 수열의 요소를 입력 받아 lst배열에 저장해 준다.
- 초기 k개의 원소를 update함수를 통해 세그먼트 트리 업데이트를 진행해 준다.
- 초기 ans의 값을 query함수를 통해 세그먼트 트리에서 (k + 1) / 2번째 큰 값으로 초기화 해준다.
- 다시 k부터 n - 1까지 인덱스를 가지는 for문을 개행해 준다.
- update 함수를 통해 이전의 요소의 값을 -1만큼 더해 제거해 준다.
- update 함수를 통해 현재 요소의 값을 1만큼 더해 추가해 준다.
- query 함수를 통해 업데이트 된 세그먼트 트리에서 (k + 1) / 2번째 큰 값을 구해 ans에 더해준다.
- 모든 탐색을 마친 후에 ans에 저장된 값을 출력해 준다.
트러블 슈팅
- 머지 소트 트리를 구현하고, 중앙 값을 구해 ans에 더해주는 식의 풀이를 진행했으나 시간 초과를 받았다.
- ans의 값을 int로 설정한 상태로 제출하였다가 Fail을 받았다.
- 최악의 경우 수열의 모든 원소가 65534일 경우 int 오버플로우가 발생함을 깨달았다.
- ans를 long long타입으로 변환 후 제출하여 AC를 받았다.
참고 사항
- 수열 내에 중복된 값이 존재할 수 있으니 업데이트 시 0, 1로 변경이 아닌 1씩 더하거나 빼주어야 한다.
정답 코드
#include<iostream>
using namespace std;
const int N = 250000;
const int P = 65535;
int n, k;
int lst[N];
int tree[P * 4];
void update(int node, int s, int e, int idx, int val) {
if (s == e) tree[node] += val;
else {
int mid = (s + e) / 2;
if (idx <= mid) update(node * 2, s, mid, idx, val);
else update(node * 2 + 1, mid + 1, e, idx, val);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
}
int query(int node, int s, int e, int idx) {
if (s == e) return s;
int mid = (s + e) / 2;
if (idx <= tree[node * 2]) return query(node * 2, s, mid, idx);
else return query(node * 2 + 1, mid + 1, e, idx - tree[node * 2]);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> k;
for (int i = 0; i < n; ++i) cin >> lst[i];
for (int i = 0; i < k; ++i) {
update(1, 0, P, lst[i], 1);
}
long long ans = query(1, 0, P, (k + 1) / 2);
for (int i = k; i < n; ++i) {
update(1, 0, P, lst[i - k], -1);
update(1, 0, P, lst[i], 1);
ans += query(1, 0, P, (k + 1) / 2);
}
cout << ans;
}
728x90
반응형
'알고리즘 공부 > C++' 카테고리의 다른 글
[P5] 백준 14727번 퍼즐 자르기 C++ 세그먼트 트리 (0) | 2025.01.30 |
---|---|
[P5] 백준 1517번 버블 소트 C++ 세그먼트 트리 (0) | 2025.01.28 |
[P3] 백준 1168번 요세푸스 문제 2 C++ 세그먼트 트리 (0) | 2025.01.27 |
[P4] 백준 12899번 데이터 구조 C++ 세그먼트 트리 (0) | 2025.01.26 |
[G5] 백준 14567번 선수과목 (Prerequisite) C++ 위상 정렬 (0) | 2025.01.25 |