포스트

[백준][2042] 구간 합 구하기

이 포스트는 백준 사이트의 구간 합 구하기 문제 풀이입니다.

문제

문제


해결 과정

이 문제는 세그먼트 트리라는 알고리즘을 사용하면 큰 값이 입력되더라도 빠르게 정답을 구할 수 있습니다.

세그먼트 트리를 사용하지 않고 주어진 명령어에 따라
매번 합을 구하고 숫자를 갱신한다면, 시간초과가 발생합니다.

따라서 임의의 구간별로 합을 미리 계산해 저장하는 세그먼트 트리를 활용하여
구간의 합을 빠르게 확인할 수 있습니다.

기존의 숫자가 새로운 숫자로 변경되면
세그먼트 트리를 순회하면서 값을 변경하면 새로운 숫자로 갱신된
세그먼트 트리를 구할 수 있습니다.

코드 구현

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <vector>

#define ll long long

using namespace std;

vector<ll> numbers;
vector<ll> tree;

void input(int& N, int& M, int& K);
ll init_tree(ll start, ll end, ll node);
void update_number(ll start, ll end, ll node, ll index, ll dif);
ll sum(ll start, ll end, ll node, ll left, ll right);


int main() {
	int N, M, K;
    input(N, M, K);

	init_tree(1, N, 1);

	for(int i = 0; i < M + K; ++i) {
		ll order, a, b;
		cin >> order >> a >> b;
		if(1 == order) {
			update_number(1, N, 1, a, b - numbers[a]);
			numbers[a] = b;
		} else if(2 == order) {
			cout << sum(1, N, 1, a, b) << '\n';
		}
	}

	return 0;
}


void input(int& N, int& M, int& K) {
    ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	cin >> N >> M >> K;
	
	numbers.assign(N + 1, 0);
	tree.assign(N * 4 + 1, 0);
	for(int i = 1; i <= N; ++i) {
		cin >> numbers[i];
	}
}

ll init_tree(ll start, ll end, ll node) {
	if(start == end) 
		return tree[node] = numbers[start];
	
	ll mid = (start + end) / 2;

	return tree[node]
	 = init_tree(start, mid, node * 2) + init_tree(mid + 1, end, node * 2 + 1);
}

void update_number(ll start, ll end, ll node, ll index, ll dif) {
	if(index < start || index > end)
		return;
	
	tree[node] += dif;

	if(start == end)
		return;
	
	ll mid = (start + end) / 2;
	update_number(start, mid, node * 2, index, dif);
	update_number(mid + 1, end, node * 2 + 1, index, dif);
}

ll sum(ll start, ll end, ll node, ll left, ll right) {
	if(left > end || right < start)
		return 0;
	if(left <= start && end <= right)
		return tree[node];
	
	ll mid = (start + end) / 2;
	return sum(start, mid, node * 2, left, right)
		+ sum(mid + 1, end, node * 2 + 1, left, right);
}


실행 결과

결과


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.