[적용한 알고리즘]
세그먼트 트리
[아이디어]
기본 문제래요
[생각의 흐름 / 절차]
내용
[교훈]
어렵
<코드>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
long long construct(vector<long long> &a, vector<long long> &tree, int node, int start, int end){
if (start == end){
return tree[node] = a[start]; // 리프 노드인 경우 자기 자신을 등록 시켜야함.
}
else {
int mid = (start + end) / 2; // 아니라면 자기 밑에 자식을 더해야 함.
return tree[node] = construct(a, tree, node * 2, start, mid) + construct(a, tree, node * 2 + 1, mid + 1, end);
}
}
void update(vector<long long> &tree, int node, int start, int end, int index, long long delta){
if (index < start || index > end) return; // 범위 밖에 있는 경우
tree[node] += delta;
if (start != end){ //리프 노드가 아닌 경우
int mid = (start + end) / 2;
update(tree, node * 2, start, mid, index, delta);
update(tree, node * 2 + 1, mid + 1, end, index, delta);
}
}
// 내가 구하고 싶은 값의 범위 : left ~ right, 현재 체크 하고 있는 노드의 범위 : start ~ end
long long sum(vector<long long> &tree, int node, int start, int end, int left, int right){
if (left > end || right < start) { // 만약에 포함이 안되어있는 경우
return 0;
}
if (left <= start && end <= right){
return tree[node];
}
int mid = (start + end) / 2;
return sum(tree, node * 2, start, mid, left, right) + sum(tree, node * 2 + 1, mid + 1, end, left, right);
}
int main(){
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
vector<long long> a(n);
int tree_height = (int)ceil(log2(n));
int tree_size = (1 << (tree_height + 1));
vector<long long> tree(tree_size);
for (int i = 0; i < n; i++){
scanf("%lld", &a[i]);
}
construct(a, tree, 1, 0, n - 1);
int t = m + k;
while (t--){
int oper;
scanf("%d", &oper);
if (oper == 1){
int x;
long long y;
scanf("%d %lld", &x, &y);
long long delta = y - a[x - 1];
a[x - 1] = y;
update(tree, 1, 0, n - 1, x - 1, delta);
}//update
if (oper == 2){
int left, right;
scanf("%d %d", &left, &right);
printf("%lld\n", sum(tree, 1, 0, n - 1, left - 1, right - 1));
}//sum
}
return 0;
}
(19/11/23 수정)
delta 를 이용하는게 덧셈에서는 유용한데, 곱하기 나누기에서는 참 곤란하다. 그래서 그냥 newVal 을 넘겨주는 식으로 짜면
코드도 더 직관적이고, 범용성도 넓어지는 것 같아서 이렇게 쓰려고 한다. (밑을 참고)
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
long long construct(vector<long long> &a, vector<long long> &tree, int node, int start, int end){
if (start == end){
return tree[node] = a[start]; // 리프 노드인 경우 자기 자신을 등록 시켜야함.
}
else {
int mid = (start + end) / 2; // 아니라면 자기 밑에 자식을 더해야 함.
return tree[node] = construct(a, tree, node * 2, start, mid) + construct(a, tree, node * 2 + 1, mid + 1, end);
}
}
long long update(vector<long long> &tree, int node, int start, int end, int index, long long newVal){
if (index < start || index > end) return tree[node]; // 범위 밖에 있는 경우
if (start == end) return tree[node] = newVal;
if (start != end){ //리프 노드가 아닌 경우
int mid = (start + end) / 2;
return tree[node] = update(tree, node * 2, start, mid, index, newVal) + update(tree, node * 2 + 1, mid + 1, end, index, newVal);
}
}
// 내가 구하고 싶은 값의 범위 : left ~ right, 현재 체크 하고 있는 노드의 범위 : start ~ end
long long sum(vector<long long> &tree, int node, int start, int end, int left, int right){
if (left > end || right < start) { // 만약에 포함이 안되어있는 경우
return 0;
}
if (left <= start && end <= right){
return tree[node];
}
int mid = (start + end) / 2;
return sum(tree, node * 2, start, mid, left, right) + sum(tree, node * 2 + 1, mid + 1, end, left, right);
}
int main(){
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
vector<long long> a(n);
int tree_height = (int)ceil(log2(n));
int tree_size = (1 << (tree_height + 1));
vector<long long> tree(tree_size);
for (int i = 0; i < n; i++){
scanf("%lld", &a[i]);
}
construct(a, tree, 1, 0, n - 1);
int t = m + k;
while (t--){
int oper;
scanf("%d", &oper);
if (oper == 1){
int x;
long long y;
scanf("%d %lld", &x, &y);
update(tree, 1, 0, n - 1, x - 1, y);
}//update
if (oper == 2){
int left, right;
scanf("%d %d", &left, &right);
printf("%lld\n", sum(tree, 1, 0, n - 1, left - 1, right - 1));
}//sum
}
return 0;
}