
리뷰

세그먼트 트리의 기초가 되는 문제인듯 싶다, 구간 업데이트 쿼리가 아닌 리프 노드까지 도달해야 하는 문제
수열과 쿼리 시리즈 부터 풀다보니 이런 기초 세그를 응용하는 문제가 약해서 생각의 폭을 넓혀야 겠다 ㅠ
https://www.acmicpc.net/problem/2243
전역 변수
- tree : 세그먼트 트리 정보를 저장할 정수형 배열, 사탕의 맛 개수가 최대 100만이므로 400만 이상의 크기로 세팅한다.
함수
1. update
void update(int node, int start, int end, int idx, int val)
- 매개변수 idx의 맛을 가진 사탕의 개수를 val만큼 더해준다.
- val에는 음수가 올 수 있으나 문제에 없는 사탕을 꺼내는 경우와 같은 잘못된 입력은 주어지지 않는다. 라고 명시되어 있다.
- 사탕을 맛있는 순서대로 누적합을 통해 세그먼트 트리를 관리해 준다.
2. query
int query(int node, int start, int end, int idx)
- 루트부터 시작하여 각 왼쪽 오른쪽 노드의 사탕 개수를 세어 사탕의 순위를 찾는 함수
- 만약 10번째 사탕의 맛을 찾고 싶은데 루트의 왼쪽이 11이고 오른쪽이 29라면 왼쪽으로 이동한다.
- 루트의 왼쪽이 9이고 오른쪽이 11이라면 오른쪽으로 이동하고 찾고자 하는 값에서 왼쪽 9만큼을 빼준다.
- 그럼 이제 오른쪽으로 이동한 상태에서 1번째 사탕의 맛을 찾아주면 된다.
- 오른쪽 노드로 이동할때의 연산을 떠오르는 것이 이 문제의 킥인 것 같다.
문제풀이
- 사탕이 없는 상태로 시작하므로 수열을 입력 받을 필요도 없고 세그먼트 트리를 build해줄 필요가 없다.
- n값을 입력 받고 n개의 쿼리를 수행해 준다, order에 따라 update와 query가 나누어 진다.
- order가 2일 경우 index, val을 추가로 입력 받고 index맛의 사탕을 val개 추가해 준 후 상위 노드를 갱신한다.
- 1일 경우 index를 추가로 입력 받고 query함수를 사용해 index번째 맛있는 사탕의 맛을 result에 저장한다.
- result를 출력해 준 후에 update함수를 통해 맛이 result인 사탕의 개수를 1만큼 줄여준다.
참고 사항
- 세그먼트 트리의 build가 필요 없고, tree는 0인상태에서 시작한다.
- 업데이트 시 음수가 입력될 수도 있다, 다만 보유한 사탕 개수가 음수가 되는 케이스는 없다.
- 탐색을 할때 오른쪽으로 가는 경우 찾고자 하는 값을 왼쪽 사탕의 개수만큼을 빼주어야 한다.
- 입력은 1-based-indexing으로 주어진다.
정답 코드
#include<iostream>
using namespace std;
int tree[4000004];
void update(int node, int start, int end, int idx, int val) {
if (idx < start || end < idx) return;
if (start == idx && end == idx) {
tree[node] += val;
return;
}
int mid = (start + end) / 2;
update(node * 2, start, mid, idx, val);
update(node * 2 + 1, mid + 1, end, idx, val);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
int query(int node, int start, int end, int idx) {
if (start == end) return start;
int mid = (start + end) / 2;
if (tree[node * 2] >= idx) return query(node * 2, start, mid, idx);
return query(node * 2 + 1, mid + 1, end, idx - tree[node * 2]);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n; cin >> n;
while (n--) {
int order; cin >> order;
if (order == 2) {
int index, val; cin >> index >> val;
update(1, 1, 1000000, index, val);
}
else {
int index; cin >> index;
int result = query(1, 1, 1000000, index);
cout << result << "\n";
update(1, 1, 1000000, result, -1);
}
}
}
728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
[G1] 백준 3665번 최종 순위 C++ 위상 정렬 (1) | 2024.09.29 |
---|---|
[P5] 백준 6549번 히스토그램에서 가장 큰 직사각형 C++ 세그먼트 트리, 분할 정복 (0) | 2024.09.28 |
[P5] 백준 20541번 앨범정리 C++ 해시맵, 문자열, 트리, 구현 (0) | 2024.09.26 |
[P4] 백준 14245번 XOR C++ 세그먼트 트리, 느리게 갱신되는 세그먼트 트리 (0) | 2024.09.26 |
[G4] 백준 2015번 수들의 합 4 C++ 해시맵, 누적합 (0) | 2024.09.26 |