백준의 구간합 구하기2(10999) 문제이다.
[ 문제 바로가기 ]
[ 문제풀이 ]
먼저 문제를 보면 구간에 대한 합을 구하는 문제이다. 구간에 대한 연산은 "세그먼트 트리" 혹은 "펜윅트리"를 이용해서 빠르고 효율적으로 해결할 수 있다.
본인은 세그먼트 트리로 이 문제에 접근해보았는데 아직 세그먼트 트리에 대해서 잘 모른다면 아래의 글을 읽고 오도록 하자.
그런데 ! 이 문제는 단순 세그먼트 트리를 이용해서 구현한다면 시간초과가 발생하게 된다. 왜냐하면 값을 업데이트 하는 것 또한 구간의 개념으로 주어지기 때문에, 제 시간 내에 연산을 다 할 수가 없다. 그래서 'Lazy Propagation' 방식을 이용해서 구현해주어야 한다. 아직 Lazy Propagation에 대해서 잘 모른다면 아래의 글을 읽고 오도록 하자.
[ Lazy Propagation 알아보기 (Click) ]
위에 링크를 걸어놓은 세그먼트 트리에 대한 설명과, Lazy Propagation 설명에 대한 글 만으로도 이 문제의 풀이를 충분히 대체할 수 있기 때문에 별다른 추가적인 설명은 진행하지 않겠다.
[ 소스코드 ]
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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #include<iostream> #include<vector> #include<cmath> #define endl "\n" #define MAX 1000010 typedef long long ll; using namespace std; int N, M, K; int Arr[MAX]; vector<ll> Lazy; vector<ll> SegmentTree; vector<pair<pair<int, int>, pair<int, int>>> Cmd; void Input() { cin >> N >> M >> K; for (int i = 0; i < N; i++) cin >> Arr[i]; for (int i = 0; i < M + K; i++) { int a; cin >> a; if (a == 1) { int b, c, d; cin >> b >> c >> d; Cmd.push_back(make_pair(make_pair(a, b), make_pair(c, d))); } else { int b, c; cin >> b >> c; Cmd.push_back(make_pair(make_pair(a, b), make_pair(c, -1))); } } } ll Make_SegmentTree(int Node, int Start, int End) { if (Start == End) return SegmentTree[Node] = Arr[Start]; int Mid = (Start + End) / 2; ll Left_Result = Make_SegmentTree(Node * 2, Start, Mid); ll Right_Result = Make_SegmentTree(Node * 2 + 1, Mid + 1, End); SegmentTree[Node] = Left_Result + Right_Result; return SegmentTree[Node]; } void Setting_SegmentTree() { int Tree_Height = (int)ceil(log2(N)); int Tree_Size = (1 << (Tree_Height + 1)); SegmentTree.resize(Tree_Size); Lazy.resize(Tree_Size); Make_SegmentTree(1, 0, N - 1); } void Lazy_Update(int Node, int Start, int End) { if (Lazy[Node] != 0) { SegmentTree[Node] = SegmentTree[Node] + (End - Start + 1) * Lazy[Node]; if (Start != End) { Lazy[Node * 2] = Lazy[Node * 2] + Lazy[Node]; Lazy[Node * 2 + 1] = Lazy[Node * 2 + 1] + Lazy[Node]; } Lazy[Node] = 0; } } void Update(int Node, int Start, int End, int Left, int Right, ll Value) { Lazy_Update(Node, Start, End); if (Right < Start || Left > End) return; if (Left <= Start && End <= Right) { SegmentTree[Node] = SegmentTree[Node] + (End - Start + 1) * Value; if (Start != End) { Lazy[Node * 2] = Lazy[Node * 2] + Value; Lazy[Node * 2 + 1] = Lazy[Node * 2 + 1] + Value; } return; } int Mid = (Start + End) / 2; Update(Node * 2, Start, Mid, Left, Right, Value); Update(Node * 2 + 1, Mid + 1, End, Left, Right, Value); SegmentTree[Node] = SegmentTree[Node * 2] + SegmentTree[Node * 2 + 1]; } ll Query(int Node, int Start, int End, int Left, int Right) { Lazy_Update(Node, Start, End); if (Right < Start || Left > End) return 0; if (Left <= Start && End <= Right) return SegmentTree[Node]; int Mid = (Start + End) / 2; ll Left_Result = Query(Node * 2, Start, Mid, Left, Right); ll Right_Result = Query(Node * 2 + 1, Mid + 1, End, Left, Right); return Left_Result + Right_Result; } void Solution() { Setting_SegmentTree(); for (int i = 0; i < M + K; i++) { int Command = Cmd[i].first.first; if (Command == 1) { int Index = Cmd[i].first.second - 1; int Index2 = Cmd[i].second.first - 1; ll Value = Cmd[i].second.second; Update(1, 0, N - 1, Index, Index2, Value); } else { int Index = Cmd[i].first.second - 1; int Index2 = Cmd[i].second.first - 1; cout << Query(1, 0, N - 1, Index, Index2) << 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 -' 카테고리의 다른 글
[ 백준 1395 ] 스위치 (C++) (0) | 2020.06.02 |
---|---|
[ 백준 11659 ] 구간 합 구하기4 (C++) (0) | 2020.05.28 |
[ 백준 1280 ] 나무 심기 (C++) (0) | 2020.05.26 |
[ 백준 1655 ] 가운데를 말해요 (C++) (5) | 2020.05.25 |
[ 백준 11658 ] 구간합 구하기3 (C++) (0) | 2020.05.24 |