백준의 구간합 구하기4(11659) 문제이다.
[ 문제 바로가기 ]
[ 문제풀이 ]
구간의 합을 구해야 하는 문제이다. 본인은 총 3가지 방법을 이용해서 문제를 해결해 보았다.
첫 번째는 간단하게 누적합을 미리 구해놓고 이 누적합을 통해서 구하는 방법이다.
이 문제는 배열의 값을 변경하는 업데이트 과정이 존재하지 않기 때문에, 단순히 누적합을 구해놓고 풀어보았다.
구체적인 과정을 알아보자. 배열이 { 1 , 2 , 3 , 4 , 5 } 가 존재한다면, 0번째 Index부터 k번째 Index까지의 합을 저장하는 누적합에 대한 배열을 하나 더 선언해 주었다.(int Sum[])
Sum[a] = b 의 의미는 "0번 Index부터 a번 Index까지의 합은 b입니다." 를 의미한다.
즉, 위의 배열({ 1, 2, 3, 4, 5}) 를 예로들어서 값을 적어보면 Sum[0] = 1 , Sum[1] = 3(1 + 2) , Sum[2] = 6(1 + 2 + 3)... 과 같은 식으로 저장이 된다.
a번에서 b번 Index까지의 값을 구하라고 한다면 Sum[b] - Sum[a - 1] 을 통해서 그 값을 구할 수 있다.
가장 간단하고 구현이 쉬운 방법이다.
두 번째는 세그먼트 트리를 이용해서 구해보았다. 값의 업데이트가 필요하지 않기 때문에 첫 번째 방법으로 구현해도 무관하지만, 세그먼트 트리로도 구현해 보았다. 세그먼트 트리에 대해서 잘 모른다면 아래의 글을 읽고 오도록 하자.
[ 세그먼트 트리(SegmentTree) 알아보기(Click) ]
세그먼트 트리에 대한 설명글만으로도 충분히 문제를 해결할 수 있기 때문에 별도의 설명은 하지 않겠다.
세 번째는 펜윅 트리를 이용해서 구해보았다. 세그먼트 트리와 마찬가지로, 값의 업데이트가 일어나지 않기 때문에 꼭 사용할 필요까지는 없지만, 펜윅트리 또한 구간에 대한 연산에서 굉장히 효율적인 자료구조 이기 때문에 이를 이용해서 구현해 보았다.
[ 펜윅트리 (FenwickTree) 알아보기(Click) ]
펜윅트리 또한 별도의 설명은 하지 않겠다.
[ 방법1. 단순 누적합을 통한 구현 소스코드 ]
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 | #include<iostream> #include<vector> #include<cmath> #define endl "\n" #define MAX 100010 using namespace std; int N, M; int Arr[MAX]; int Sum[MAX]; vector<pair<int, int>> Cmd; void Input() { cin >> N >> M; for (int i = 1; i <= N; i++) { cin >> Arr[i]; Sum[i] = Sum[i - 1] + Arr[i]; } for (int i = 0; i < M; i++) { int a, b; cin >> a >> b; Cmd.push_back(make_pair(a, b)); } } void Solution() { for (int i = 0; i < M; i++) { int Start = Cmd[i].first; int End = Cmd[i].second; cout << Sum[End] - Sum[Start - 1] << endl; } } void Solve() { Input(); Solution(); } int main(void) { ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); //freopen("Input.txt", "r", stdin); Solve(); return 0; } | cs |
[ 방법2. 세그먼트 트리를 이용한 소스코드 ]
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 | #include<iostream> #include<vector> #include<cmath> #define endl "\n" #define MAX 100010 using namespace std; int N, M; int Arr[MAX]; vector<int> SegmentTree; vector<pair<int, int>> Cmd; void Input() { cin >> N >> M; for (int i = 1; i <= N; i++) cin >> Arr[i]; for (int i = 0; i < M; i++) { int a, b; cin >> a >> b; Cmd.push_back(make_pair(a, b)); } } int Make_SegmentTree(int Node, int Start, int End) { if (Start == End) return SegmentTree[Node] = Arr[Start]; int Mid = (Start + End) / 2; int Left_Result = Make_SegmentTree(Node * 2, Start, Mid); int Right_Result = Make_SegmentTree(Node * 2 + 1, Mid + 1, End); return SegmentTree[Node] = Left_Result + Right_Result; } int Query(int Node, int Start, int End, int Left, int Right) { if (Right < Start || Left > End) return 0; if (Left <= Start && End <= Right) return SegmentTree[Node]; int Mid = (Start + End) / 2; int Left_Result = Query(Node * 2, Start, Mid, Left, Right); int Right_Result = Query(Node * 2 + 1, Mid + 1, End, Left, Right); return Left_Result + Right_Result; } void Solution() { int Tree_Height = (int)ceil(log2(N)); int Tree_Size = 1 << (Tree_Height + 1); SegmentTree.resize(Tree_Size); Make_SegmentTree(1, 1, N); for (int i = 0; i < M; i++) { int Idx = Cmd[i].first; int Idx2 = Cmd[i].second; cout << Query(1, 1, N, Idx, Idx2) << endl; } } void Solve() { Input(); Solution(); } int main(void) { ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); //freopen("Input.txt", "r", stdin); Solve(); return 0; } | cs |
[ 방법3. 펜윅트리를 이용한 소스코드 ]
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 | #include<iostream> #include<vector> #include<cmath> #define endl "\n" #define MAX 100010 using namespace std; int N, M; int Arr[MAX]; vector<int> FenwickTree; vector<pair<int, int>> Cmd; void Input() { cin >> N >> M; for (int i = 1; i <= N; i++) cin >> Arr[i]; for (int i = 0; i < M; i++) { int a, b; cin >> a >> b; Cmd.push_back(make_pair(a, b)); } } void Update(int Idx, int Value) { while (Idx < FenwickTree.size()) { FenwickTree[Idx] = FenwickTree[Idx] + Value; Idx = Idx + (Idx & -Idx); } } int Sum(int Idx) { int Result = 0; while (Idx > 0) { Result = Result + FenwickTree[Idx]; Idx = Idx - (Idx & -Idx); } return Result; } void Solution() { FenwickTree.resize(N + 1); for (int i = 1; i <= N; i++) Update(i, Arr[i]); for (int i = 0; i < M; i++) { int Start = Cmd[i].first; int End = Cmd[i].second; cout << Sum(End) - Sum(Start - 1) << endl; } } void Solve() { Input(); Solution(); } int main(void) { ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); //freopen("Input.txt", "r", stdin); Solve(); return 0; } | cs |
'[ BOJ Code ] > # BOJ -' 카테고리의 다른 글
[ 백준 2293 ] 동전1 (C++) (8) | 2020.06.04 |
---|---|
[ 백준 1395 ] 스위치 (C++) (0) | 2020.06.02 |
[ 백준 10999 ] 구간합 구하기2 (C++) (1) | 2020.05.27 |
[ 백준 1280 ] 나무 심기 (C++) (0) | 2020.05.26 |
[ 백준 1655 ] 가운데를 말해요 (C++) (5) | 2020.05.25 |