"구간을 저장하기 위한 트리"
→ 여러 개의 데이터가 연속적으로 존재할 때, 특정한 범위의 데이터의 합을 구하는 방법
총 시간 복잡도 : O(lgN)
ex) N = 10
각 노드가 저장하고 있는 합의 범위를 나타낸 그림
각 노드의 index 번호
// a: 배열 a
// tree: 세그먼트 트리
// node: 세그먼트 트리 노드 번호
// node가 담당하는 합의 범위가 start ~ end
long long init(vector<long long> &a, vector<long long> &tree, int node, int start, int end) {
if (start == end) { // Leaf 노드
return tree[node] = a[start];
} else { // 다른 노드
return tree[node] = init(a, tree, node*2, start, (start+end)/2) + init(a, tree, node*2+1, (start+end)/2+1, end);
}
}
: 구간 left, right가 주어졌을 때, 합 찾기 위해 루트부터 트리 순회하며 각 노드가 담당하는 구간과 left, right사이의 관계 살펴봐야 한다.
ex) 3~9까지의 합 구하기
node가 담당하고 있는 구간이 [start,end] 이고, 합을 구해야하는 구간이 [left,right] 이라면 다음과 같이 4가지 경우
// node가 담당하는 구간이 start~end이고, 구해야하는 합의 범위는 left~right
long long sum(vector<long long> &tree, int node, int start, int end, int left, int right) {
if (left > end || right < start) { // 1번
return 0;
}
if (left <= start && end <= right) { // 2번
return tree[node];
}
// 3번 & 4번
return sum(tree, node*2, start, (start+end)/2, left, right) + sum(tree, node*2+1, (start+end)/2+1, end, left, right);
}
: 중간에 수 변경할 경우, 그 숫자가 포함된 구간을 담당하는 노드를 모두 변경해야 한다.
ex) 3번째 수를 변경하는 경우
수 변경은 2가지 경우
void update(vector<long long> &tree, int node, int start, int end, int index, long long diff) {
if (index < start || index > end) return; // 포함 X
// 포함 O
tree[node] = tree[node] + diff;
if (start != end) { // Leaf 노드가 아닌 경우, 자식도 변경
update(tree,node*2, start, (start+end)/2, index, diff);
update(tree,node*2+1, (start+end)/2+1, end, index, diff);
}
}