본문 바로가기

문제 풀이/BOJ

[백준 2042] 구간 합 구하기

1. 문제 

 

https://www.acmicpc.net/problem/2042

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net


2. 풀이

 

기본적인 세그먼트 트리 문제이다. 나는 세그먼트 트리보다 인덱스 트리를 선호하므로 인덱스 트리로 설명하겠다. 인덱스 트리에 대해 잘 모른다면 먼저 공부하고 오자!

인덱스 트리 : https://kinngife.tistory.com/32

 

인덱스 트리 (Binary Indexed Tree)

1. 정의 인덱스 트리는 원소들의 구간 합을 빠르게 구하기 위해 사용하는 자료구조로 펜윅 트리라고도 한다. 세그먼트 트리와 같이 기능을 하지만 구현이 좀 더 쉽고 직관적이며 많은 문제에 활

kinngife.tistory.com

 

N이 최대 100만이므로 100만보다 처음으로 크거나 같아지는 2의 제곱수는 1,048,576이다. 이 값을 $OFFSET$이라고 하였을 때, 인덱스 트리를 나타내는 tree 배열은 $OFFSET$ * 2만큼의 크기가 필요하다. N개의 수를 arr 배열에 입력받고 init 함수를 통해 tree 배열을 초기화한다.

 

int OFFSET = 1048576;
vector<ll>arr(1000001);
vector<ll>tree(OFFSET * 2);

void init() {
	for (int i = 0; i < N; i++) tree[i + OFFSET] = arr[i];
	for (int i = OFFSET - 1; i > 0; i--) tree[i] = tree[2 * i] + tree[2 * i + 1];
}

 

다음 M+K 줄에 걸쳐 정수 a, b, c를 입력받는데, a가 1인 경우에는 update 함수를 통해 tree 배열을 update 하고, a가 2인 경우에는 query 함수를 통해 구간 합을 출력한다. 입력받는 정수의 범위가 long long형이므로 int형으로 선언하여 틀리는 것에 주의한다.

 

void update(ll idx, ll num) {
	idx += OFFSET;
	tree[idx] = num;
	while (idx > 1) {
		idx /= 2;
		tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
	}
}
ll query(ll left, ll right) {
	ll ret = 0;
	left += OFFSET, right += OFFSET;
	while (left <= right) {
		if (left % 2 == 1) ret += tree[left++];
		if (right % 2 == 0) ret += tree[right--];
		left /= 2, right /= 2;
	}
	return ret;
}

 


3. 전체 코드

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <cmath>
#define INF INT_MAX
using namespace std;
using ll = long long;
using ii = pair<int, int>;
int N, M, K;
int OFFSET = 1048576;
vector<ll>arr(1000001);
vector<ll>tree(OFFSET * 2);

void init() {
	for (int i = 0; i < N; i++) tree[i + OFFSET] = arr[i];
	for (int i = OFFSET - 1; i > 0; i--) tree[i] = tree[2 * i] + tree[2 * i + 1];
}
void update(ll idx, ll num) {
	idx += OFFSET;
	tree[idx] = num;
	while (idx > 1) {
		idx /= 2;
		tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
	}
}
ll query(ll left, ll right) {
	ll ret = 0;
	left += OFFSET, right += OFFSET;
	while (left <= right) {
		if (left % 2 == 1) ret += tree[left++];
		if (right % 2 == 0) ret += tree[right--];
		left /= 2, right /= 2;
	}
	return ret;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	cin >> N >> M >> K;
	for (int i = 0; i < N; i++) cin >> arr[i];
	
	init();

	M += K;
	while (M--) {
		ll a, b, c; cin >> a >> b >> c;
		if (a == 1) update(b - 1, c);
		else cout << query(b - 1, c - 1) << "\n";
	}

	return 0;
}

'문제 풀이 > BOJ' 카테고리의 다른 글

[백준 2243] 사탕상자  (0) 2023.02.20
[백준 2517] 달리기  (0) 2023.02.16
[백준 16197] 두 동전  (0) 2022.07.31
[백준 2630] 색종이 만들기  (0) 2022.07.24
[백준 9663] N-Queen  (0) 2022.07.18