백준 2042번 (구간 합 구하기, C++) [BAEKJOON]

구간 합 구하기

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

시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초256 MB86858206901061524.949%

문제

어떤 N개의 수가 주어져 있다.

그런데 중간에 수의 변경이 빈번히 일어나고 그 중간에 어떤 부분의 합을 구하려 한다.

만약에 1,2,3,4,5 라는 수가 있고, 3번째 수를 6으로 바꾸고 2번째부터 5번째까지 합을 구하라고 한다면 17을 출력하면 되는 것이다.

그리고 그 상태에서 다섯 번째 수를 2로 바꾸고 3번째부터 5번째까지 합을 구하라고 한다면 12가 될 것이다.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다.

M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다.

그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다.

그리고 N+2번째 줄부터 N+M+K+1번째 줄까지 세 개의 정수 a, b, c가 주어지는데,

a가 1인 경우 b(1 ≤ b ≤ N)번째 수를 c로 바꾸고

a가 2인 경우에는 b(1 ≤ b ≤ N)번째 수부터 c(b ≤ c ≤ N)번째 수까지의 합을 구하여 출력하면 된다.

입력으로 주어지는 모든 수는 -263보다 크거나 같고, 263-1보다 작거나 같은 정수이다.

출력

첫째 줄부터 K줄에 걸쳐 구한 구간의 합을 출력한다.

단, 정답은 -263보다 크거나 같고, 263-1보다 작거나 같은 정수이다.

예제 입력 1

5 2 2
1
2
3
4
5
1 3 6
2 2 5
1 5 2
2 3 5

예제 출력 1

17
12

예제 입력 A

1 1 2
5000000000000000000
2 1 1
1 1 -5000000000000000000
2 1 1

예제 출력 A

5000000000000000000
-5000000000000000000

예제 입력 B

5 2 2
1
2
3
4
5
1 3 6
2 2 5
1 3 7
2 2 5

예제 출력 B

17
18

출처

알고리즘 분류


참고 자료

세그먼트 트리를 이해하는데 아래의 강의와 링크에 많은 도움을 받았다.

https://blog.garybricks.com/segment-tree-introduction-in-c

통과된 코드

세그먼트 트리(Segment Tree)를 이용하여 구간합을 구하는 문제

#include <iostream>
using namespace std;
typedef long long ll;
int _N, _M, _K;
int _SegSize, _Num;
ll* _Numbers;
ll* _SegmentTree;

void InitSegTree()
{
    _Num = 1;
    while (_Num < _N)
        _Num *= 2;
    _SegSize = _Num * 2;
    _SegmentTree = new ll[_SegSize]();
    for (int i = _Num, j = 0; j < _N; j++)
        _SegmentTree[i + j] = _Numbers[j + 1];
    for (int i = _SegSize / 2 - 1; i > 0; i--)
        _SegmentTree[i] = _SegmentTree[i * 2] + _SegmentTree[i * 2 + 1];
}

void Update(int _Index, long long Value)
{
    _Index += _SegSize / 2 - 1;
    _SegmentTree[_Index] = Value;
    while (_Index != 0) {
        _Index /= 2;
        _SegmentTree[_Index] = _SegmentTree[_Index * 2] + _SegmentTree[_Index * 2 + 1];
    }
}

ll Sum(int _s, int _e)
{
    ll _Res = 0;
    while (_s <= _e) {
        if (_s % 2 == 1)
            _Res += _SegmentTree[_s];
        if (_e % 2 == 0)
            _Res += _SegmentTree[_e];
        _s = (_s + 1) / 2;
        _e = (_e - 1) / 2;
    }
    return _Res;
}

int main() {

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> _N >> _M >> _K;
    _Numbers = new ll[_N + 1]();
    for (int i = 1; i <= _N; i++)
        cin >> _Numbers[i];
    InitSegTree();

    ll _t1, _t2, _O;
    while (_M + _K > 0) {
        cin >> _O >> _t1 >> _t2;
        if (_O == 1) {
            Update(_t1, _t2);
            _M--;
        }
        else if (_O == 2) {
            cout << Sum(_t1 + _Num - 1, _t2 + _Num - 1) << "\n";
            _K--;
        }
    }
    return 0;
}

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤