Algorithm & Data Structures/Data Structures
Segment Tree <세그먼트 트리>
Geisha
2024. 2. 27. 13:32
세그먼트트리

class SegmentTree {
long tree[]; // 세그먼트 트리 배열
int treeSize; // 트리의 크기
// 세그먼트 트리 생성자
public SegmentTree(int arrSize) {
// 배열 크기에 맞게 트리의 높이 계산
int h = (int) Math.ceil(Math.log(arrSize) / Math.log(2));
// 트리의 크기 계산
this.treeSize = (int) Math.pow(2, h + 1);
// 트리 배열 생성
this.tree = new long[treeSize];
}
// 세그먼트 트리 초기화 메서드
public long init(long[] arr, int node, int start, int end) {
// 시작과 끝이 같으면 leaf 노드이므로 해당 값으로 초기화
if (start == end) {
return tree[node] = arr[start];
}
// leaf 노드가 아니면, 자식 노드의 합을 저장
return tree[node] = init(arr, node * 2, start, (start + end) / 2)
+ init(arr, node * 2 + 1, (start + end) / 2 + 1, end);
}
// 세그먼트 트리 값 갱신 메서드
public void update(int node, int start, int end, int idx, long diff) {
if (idx < start || end < idx) return;
// 차이를 현재 노드에 반영
tree[node] += diff;
// leaf 노드가 아니면 자식 노드도 갱신
if (start != end) {
update(node * 2, start, (start + end) / 2, idx, diff);
update(node * 2 + 1, (start + end) / 2 + 1, end, idx, diff);
}
}
// 세그먼트 트리 구간 합 계산 메서드
public long sum(int node, int start, int end, int left, int right) {
// 범위가 벗어나면 0 반환
if (left > end || right < start) return 0;
// 범위가 완전히 포함되면 해당 노드 값 반환
if (left <= start && end <= right) return tree[node];
// 그 외의 경우 좌/우측으로 분할하여 계산
return sum(node * 2, start, (start + end) / 2, left, right)
+ sum(node * 2 + 1, (start + end) / 2 + 1, end, left, right);
}
}
//====================================================================================
// 같은코드 압축된 코드
class SegmentTree {
long tree[];
int treeSize;
public SegmentTree(int arrSize) {
int h = (int) Math.ceil(Math.log(arrSize) / Math.log(2));
treeSize = (int) Math.pow(2, h + 1);
tree = new long[treeSize];
}
public long init(long[] arr, int node, int start, int end) {
return start == end ? tree[node] = arr[start] : (tree[node] = init(arr, node * 2, start, (start + end) / 2) + init(arr, node * 2 + 1, (start + end) / 2 + 1, end));
}
public void update(int node, int start, int end, int idx, long diff) {
if (idx < start || end < idx) return;
tree[node] += diff;
if (start != end) {
update(node * 2, start, (start + end) / 2, idx, diff);
update(node * 2 + 1, (start + end) / 2 + 1, end, idx, diff);
}
}
public long sum(int node, int start, int end, int left, int right) {
if (left > end || right < start) return 0;
return (left <= start && end <= right) ? tree[node] : (sum(node * 2, start, (start + end) / 2, left, right) + sum(node * 2 + 1, (start + end) / 2 + 1, end, left, right));
}
}
세그먼트 트리는 배열 또는 리스트와 같은 데이터 구조를 사용하여 구간에 대한 질의를 효율적으로 처리하는 자료구조입니다. 이를 통해 주어진 구간에 대한 최솟값, 최댓값 또는 합 등을 빠르게 계산할 수 있습니다. 보통 이진 트리의 형태를 가지며, 재귀적으로 구간을 분할하여 각 구간의 값을 저장하고 관리합니다.
logN 의시간이 걸리며 수정이되면 수정이 전체 트리에 반영된다.
변경에도 M번 변경시 M(logN) 의 시간이 걸린다.