https://www.acmicpc.net/problem/2243
인덱스 트리를 활용하여 해결했다.
앞선 인덱스 트리를 활용하는 문제들과 같이, 이 문제도 말만 다르지, 결국 원소 업데이트가 빈번하게 일어나는 동시에 구간합을 구하는 문제이다.
특정 맛의 사탕을 빼거나 더하는 것은, 인덱스 트리의 기본적인 업데이트 쿼리와 동일하기 때문에 따로 설명하지는 않을 것이고, 특정 순위의 사탕을 가져오는 부분에 대해서만 살펴보겠다.
a == 1인 경우에 k번째 순위를 가지는 사탕을 가져와야 하는 상황이다.
root에서부터 노드 하나하나가 사탕의 개수를 구간합으로 가지고 있는 형태로 트리를 만들어준다. leaf 노드의 수는 가능한 맛의 범위로 잡아주면 된다. 이 문제에서는 100 만이었던 것으로 기억한다.
이렇게 leaf 노드는 그 맛의 사탕이 몇 개 있다는 것을 의미한다.
이제 k번째 순위의 사탕을 찾는다고 하면, 트리의 왼쪽에서부터(가장 맛있는 사탕부터) k번째인 것이다. 이때 k보다 한 노드의 값(거기까지 구간합)이 크다면 그 노드의 자손 부분에 우리가 찾는 k번째 사탕이 존재한다는 의미이므로 계속 아래로 내려가준다.
반대로 k보다 작다면, 우리가 찾는 k번째 사탕이 그 노드의 오른쪽 트리에 있다는 것이기 때문에 오른쪽으로 이동해주고, 왼쪽에 있는 사탕의 개수(확인했던 구간합의 값)만큼 k를 감소시켜준다.
또한 리트 노드에 도달했다면 위의 작업을 해줄 필요가 없기 때문에, 리프 노드인지 아닌지 확인해 주는 작업을 함께 진행해주면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include<iostream> #define MAX 1000000 using namespace std; int idxT[4 * MAX+2], start = 1; void Update(int idx, int delta) { while (idx > 0) { idxT[idx] += delta; idx /= 2; } } int getCandy(int k) { int i = 1; while (1) { if (idxT[i] >= k) { //이 지점의 서브트리에 우리가 찾는 사탕이 속해 있다면 if (i >= start && i < start + MAX) { //그 지점이 leaf라면 종료 Update(i, -1); return i - start + 1; } i *= 2; //leaf가 아니라면 이어서 탐색 continue; } else { //이 지점이 아닌 반대쪽에 우리가 찾는 사탕이 있다면 k = k - idxT[i]; i++; continue; } } } int main(void) { ios::sync_with_stdio(false); cin.tie(0); while (start < MAX) //MAX보다 크거나 같으면서 가장 큰 2의 제곱수 start *= 2; int n; cin >> n; //쿼리의 수 for (int i = 0, a, b, c ; i < n; i++) { cin >> a >> b; if (a == 1) cout << getCandy(b) << '\n'; //사탕 꺼내기 else { cin >> c; //사탕의 변화량 Update(b + start - 1, c); } } return 0; } | cs |
'알고리즘 문제 풀이 > 백준 온라인 저지' 카테고리의 다른 글
백준 1717 집합의 표현 C++ (0) | 2019.08.14 |
---|---|
백준 10451 순열 사이클 C++ (0) | 2019.08.14 |
백준 1275 커피숍2 C++ (0) | 2019.08.14 |
백준 5639 이진 검색 트리 C++ (0) | 2019.08.14 |
백준 6416 트리인가? C++ (0) | 2019.08.13 |