[C++]구간 합 구하기(Segment) - 백준2042
문제
풀이
문제 해석을 하자면,
- 문제를 읽어보면 알겠지만 전형적인 Segment Tree 문제이다.
- Segment Tree는 구간합을 구하는데 특화된 트리인데 특히 중간에 수의 변경이 빈번히 일어나는 경우에 더욱 성능이 좋은 자료구조이다.
- 따라서 이 문제는 Segment Tree를 구현하는 문제로 볼 수 있다.
풀이
- 이전에 Segment Tree를 구현한 코드가 있어서 해당 게시물 참고바람
- 추가로 생각할점은 b번째 수를 c로 바꾸는건
c-inArr[b-1]
로 바꿔야 한다는 의미란 것!! - 또한, 추가로 배열 크기를 굉장히 크게 잡아야한다.
- 2백만이면 충분할줄 알고 했다가 안풀려서 5백만으로 올리니까 정답처리 되었다.
코드
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
long long inArr[2000010];
long long outArr[5000010];
long long segmentBuild(int start, int end, int node) {
if (start == end) {
outArr[node] = inArr[start];
return outArr[node]; // 종료시점
}
int mid = (start + end) / 2; // mid 구해서 왼, 오 구간 나눔
outArr[node] = segmentBuild(start, mid, node * 2) + segmentBuild(mid + 1, end, node * 2 + 1);
return outArr[node]; // 끝
}
// 구하는 합 구간 left, right
// node가 담당하는 구간 start, end
long long segmentSum(int start, int end, int node, long long left, long long right) {
// 1. 겹치지 않는 경우 (왼쪽이거나 오른쪽 구간인경우)
if ((left < start && right < start) || (left > end && right > end)) return 0;
// 2. left, right가 start, end를 완전히 포함하는 경우
if (left <= start && right >= end) return outArr[node];
// 3. 나머지 경우 (자식 트리 탐색)
int mid = (start + end) / 2;
return segmentSum(start, mid, node * 2, left, right) + segmentSum(mid + 1, end, node * 2 + 1, left, right);
}
// node가 담당하는 구간 start, end
// 수정할 노드 index, 수정할 값 dif
void segmentUpdate(int start, int end, int node, long long index, long long dif) {
// 1. 겹치지 않는 경우 (왼쪽이거나 오른쪽 구간인경우)
if ((start < index && end < index) || (start > index && end > index)) return;
// 2. left, right가 start, end를 완전히 포함하는 경우
if (start <= index && index <= end) outArr[node] += dif;
// 무조건 종료시점(무한루프 안걸리게)
if (start == end) return;
// 3. 나머지 경우 (자식 트리 탐색)
int mid = (start + end) / 2;
segmentUpdate(start, mid, node * 2, index, dif);
segmentUpdate(mid + 1, end, node * 2 + 1, index, dif);
}
int N, M, K;
int main() {
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
cin >> N >> M >> K;
for (int i = 0; i < N; i++) {
cin >> inArr[i];
}
segmentBuild(0, N-1, 1); // outArr 수정(index 1부터 저장)
long long a = 0;
long long b = 0;
long long c = 0;
for (int i = 0; i < M + K; i++) {
cin >> a >> b >> c;
if (a == 1) {
// b번째 수를 c로 바꾸는건 `c-inArr[b-1]` 로 바꿔야 한다는 의미이다.
segmentUpdate(0, N-1, 1, b-1, c-inArr[b-1]);
inArr[b - 1] = c; // b->c로 변환 (`c-inArr[b-1]` 에 사용되니까 바꿔줘야함)
}
else if (a == 2) {
cout << segmentSum(0, N-1, 1, b-1, c-1) << '\n';
}
}
return 0;
}
느낀점
생략
댓글남기기