반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- upper_bound
- compose
- @P0
- 기술면접
- 소프티어
- Kafka
- 13908
- 연결요소
- 파라메트릭
- softeer
- 백준
- Docker
- 백트래킹
- incr
- 경력
- boj #19237 #어른 상어
- BFS
- BOJ
- 6987
- 성적평가
- 처우산정
- 물채우기
- 퇴사통보
- msSQL
- 이분탐색
- OFFSET
- dfs
- 매개변수탐색
- 처우협의
- 오퍼레터
Archives
- Today
- Total
기술 블로그
세그먼트 트리(Segment Tree) 본문
728x90
반응형
https://www.acmicpc.net/blog/view/9
세그먼트 트리(Segment Tree)
세그먼트 트리의 루트 노드는 0이 아닌 1부터 시작한다.(1, ...)
배열, vector의 인덱스 번호는 1이 아닌 0부터 시작한다.
함수의 인자들 중에서 node를 제외한 모든 것들은
vector 또는 배열과 관련된 값들(인덱스, 값 자체 등)이라고 생각하면 된다.
초기 세그먼트 트리 설정하기
1 2 3 4 5 6 | long long init_segment_tree(int node, int start, int end) { if (start == end) return tree[node] = v[start]; return tree[node] = init_segment_tree(2 * node, start, (start + end) / 2) + init_segment_tree(2 * node + 1, (start + end) / 2 + 1, end); } | cs |
왼쪽 자식 : 2 * node
오른쪽 자식 : (2 * node) + 1
합 구하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 합 구하기 long long sum(int node, int start, int end, int left, int right) { // [left, right]와 [start, end]가 겹치지 않는 경우 if (left > end || right < start) return 0; // [left, right]가 [start, end]를 완전히 포함하는 경우 if (left <= start && end <= right) return tree[node]; // [start, end]가 [left, right]를 완전히 포함하는 경우와 // [left, right]와 [start, end]가 겹쳐져 있는 경우(위의 3개를 제외 나머지 경우) return sum(2 * node, start, (start + end) / 2, left, right) + sum(2 * node + 1, (start + end) / 2 + 1, end, left, right); } | cs |
수 변경하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 수 변경하기(index번 째 수를 변경) void update(int node, int start, int end, int index, long long diff) { // [start, end]에 index가 포함되지 않는 경우 if (index < start || end < index) return; // [start, end]에 index가 포함되는 경우 tree[node] += diff; // 직접적인 세그먼트 트리 내에 있는 배열의 수 변경 // 리프 노드가 아닌 경우에는 자식도 변경해줘야 하기 때문에 // start != end로 리프 노드인지 검사한다.(같으면 리프 노드임) if (start != end) { update(node, start, (start + end) / 2, index, diff); update(node, (start + end) / 2 + 1, end, index, diff); } } | cs |
BOJ 2042번 구간 합 구하기
https://www.acmicpc.net/problem/2042
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 | #include <bits/stdc++.h> using namespace std; int N, M, K; vector<long long> v, tree; // 초기 세그먼트 트리 설정하기 long long init_segment_tree(int node, int start, int end) { if (start == end) return tree[node] = v[start]; return tree[node] = init_segment_tree(2 * node, start, (start + end) / 2) + init_segment_tree(2 * node + 1, (start + end) / 2 + 1, end); } // 합 구하기 long long sum(int node, int start, int end, int left, int right) { // [left, right]와 [start, end]가 겹치지 않는 경우 if (left > end || right < start) return 0; // [left, right]가 [start, end]를 완전히 포함하는 경우 if (left <= start && end <= right) return tree[node]; // [start, end]가 [left, right]를 완전히 포함하는 경우와 // [left, right]와 [start, end]가 겹쳐져 있는 경우(위의 3개를 제외 나머지 경우) return sum(2 * node, start, (start + end) / 2, left, right) + sum(2 * node + 1, (start + end) / 2 + 1, end, left, right); } // 수 변경하기(index번 째 수를 변경) void update(int node, int start, int end, int index, long long diff) { // [start, end]에 index가 포함되지 않는 경우 if (index < start || end < index) return; // [start, end]에 index가 포함되는 경우 tree[node] += diff; // 직접적인 세그먼트 트리 내에 있는 배열의 수 변경 // 리프 노드가 아닌 경우에는 자식도 변경해줘야 하기 때문에 // start != end로 리프 노드인지 검사한다.(같으면 리프 노드임) if (start != end) { update(2 * node, start, (start + end) / 2, index, diff); update(2 * node + 1, (start + end) / 2 + 1, end, index, diff); } } int main(void) { int a; long long input; scanf("%d %d %d", &N, &M, &K); for (int i = 0; i < N; i++) { scanf("%lld", &input); v.push_back(input); } int h = (int)ceil(log2(N)); int tree_size = 1 << (h + 1); // 세그먼트 트리 크기 tree.assign(tree_size, 0); // 할당 // 0하고 N - 1은 v vector에 대한 인덱스다. init_segment_tree(1, 0, N - 1); for (int i = 0; i < M + K; i++) { scanf("%d", &a); // b번 째 수를 c로 변경 if (a == 1) { int b; long long c; scanf("%d %lld", &b, &c); --b; // b는 vector에 대한 인덱스이므로 1 감소. long long diff = c - v[b]; v[b] = c; update(1, 0, N - 1, b, diff); } else if (a == 2) // b번째 수 ~ c번째 수까지의 합 { int b, c; scanf("%d %d", &b, &c); --b; --c; // b와 c는 vector에 대한 인덱스이므로 1씩 감소. // 1은 루트 노드 번호, 0과 N - 1 그리고 b와 c는 v vector에 대한 인덱스 번호 printf("%lld\n", sum(1, 0, N - 1, b, c)); } } return 0; } | cs |
728x90
반응형
'알고리즘' 카테고리의 다른 글
해쉬 테이블(Hash Table) (0) | 2019.08.25 |
---|---|
다익스트라(Dijkstra) (0) | 2019.08.17 |
Next Greater Element(NGE) (0) | 2019.07.06 |
2차원 배열을 함수 인자로 전달(포인터) (0) | 2019.07.01 |
SPFA (Shortest Path Faster Algorithm) (0) | 2019.06.01 |