336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
세그먼트 트리에 대해 정리.
1) 세그트리 구성에 필요한 크기
2) 세그트리 노드정보
3) 세그트리 초기화
4) 세그트리의 정보얻기
5) 세그트리 노드정보 업데이트
이진트리로 구성된 트리로
먼저, int형 데이터가 N개가 있다고 할 때, 데이터들 중 최소값을 찾으려면 모든 값을 비교하여 찾을 때, O(N) 번 연산을 해야 최소값을 찾을 수 있다.
하지만 세그트리는 이러한 연산을 O(1) 만에 해결할 수 있다. 이러한 이유는 각 트리의 노드에 구간정보를 저장하고 있기 때문이다.
또한, 특정 구간을 찾으려면 O(logN) 만에 찾을 수 있다.
자식이 있는 "부모노드"는 구간에 대한 정보를 가지고 있는다.
자식이 없는 "리프노드"는 하나의 정보만 가지고 있는다.
1) 세그트리 구성에 필요한 크기
세그트리의 노드 수는 데이터가 N개 일 때,
N <= 리프노드의 수 로 만들어 주면 된다.
8개의 데이터가 필요하므로 리프노드는 2^3개가 필요하다.
총 필요한 노드의 수는 리프노드의 수 + 부모노드의 수 이다.
= 2^3 + 2^2 + 2^1 + 2^0
즉 총 15개가 필요하다. 그러므로 만들어야 하는 배열의 크기는 2^(높이+1) - 1 만큼의 공간이 필요하다.
배열인덱스 0은 사용하지 않으므로 -1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include<cstdio> #include<cmath> typedef int type; vector<type> input; vector<type> seg; const INF = 987654321; int main(){ scanf("%d", &n); for(int i = 0 ; i < n ; i++) scanf("%d", &input[i]); // input int h = ceil(log2(n)); seg = vector<type>(1 << (h+1) ); // seg tree return 0; } | cs |
8개의 데이터를 가지고 있다고 하자. 이때 세그트리의 모양은 아래와 같다.
2) 세그트리 노드의 정보
각 노드의 위에 위치한 번호는 배열의 인덱스이다.
그리고 노드안에 속한 값은 [a,b] : a, b를 포함한 a와 b 사이 구간정보를 갖고있는다.
배열 인덱스 0을 사용하지 않고,
배열 인덱스를 1부터 사용하는 이유는 부모노드가 자식노드로 가기 위해서 이다.
P ; 부모노드 인덱스
C1 , C2 ; 자식노드 인덱스라 하면,
C1 = 2*P
C2 = 2*P + 1
으로 배열에 위치한 자식노드로 갈 수 있다.
처음에 구간트리에 정보를 올리기 위해서는 데이터를 모두 다 받아야 한다.
위 트리에서는 8개의 정보를 가지고 있는 배열을 입력받아 구간트리의 정보를 업데이트 할 수 있다.
3) 세그트리 초기화
input ; 입력으로 데이터 정보를 담고 있는 vector
seg ; 구간트리를 만들 vector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 세그트리 초기화 typedef int type; vector<type> input; vector<type> seg; type mn2(type a, type b){ return (a > b)? b : a; } // 최소값을 return type init(int node, int s, int e){ if(s == e) return seg[node] = input[start]; // start 와 end 의 위치가 일치하면 input[start] 값을 넣어준다. return seg[node] = mn2(init(2*node, s, (s+e)/2) , init(2*node+1, (s+e)/2 + 1, e) ); // 다른 노드들의 정보를 } | cs |
리프노드의 경우에는 값을 가져야 하므로 input이 가진 값을 가지게 되고,
나머지 부모노드들은 구간정보를 가지고 있게 합니다.
4) 세그트리의 정보얻기
구간정보를 얻기위해서 query를 작성합니다.
이때 구간정보를 얻기위해 구간들이 생기는 경우는 총 4개입니다.
위 그림과 같이
1) 찾아내야 할 구간과 노드가 가진 정보구간이 겹치지 않는 경우.
2) 찾아내야 할 구간안에 노드가 가진 정보구간이 포함되는 경우.
3) 찾아내야 할 구간과 노드가 가진 정보구간이 부분적으로 겹치는 경우.
4) 찾아내야 할 구간이 노드가 가진 정보구간 안에 포함되는 경우.
이 경우들을 보면
1) 찾아내야 할 구간과 노드가 가진 정보구간이 겹치지 않는 경우.
더이상 탐색하는 것이 무의미. query와 상관없는 값을 return 해주면 된다.
2) 찾아내야 할 구간안에 노드가 가진 정보구간이 포함되는 경우.
더이상 탐색하는 것이 무의미. 현재 가진 정보 구간의 값을 return 해주면 된다.
3) 찾아내야 할 구간과 노드가 가진 정보구간이 부분적으로 겹치는 경우.
4) 찾아내야 할 구간이 노드가 가진 정보구간 안에 포함되는 경우.
이 두 경우는 탐색을 계속 진행한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | typedef int type; vector<type> input; vector<type> seg; const INF = 987654321; type mn2(type a, type b){ return (a > b)? b : a; } // 최소값을 return // s-e : 노드정보구간 // l-r : 찾을정보구간 type query(int node, int s, int e, int l, int r){ if(e < l || r < s) return INF; // 1 if(l <= s && e <= r) return seg[node]; // 2 return mn2(query(2*node, s, (s+e)/2 + 1, l, r), query(2*node + 1, (s+e)/2 + 1, e, l, r) ); // 3, 4 } | cs |
위와 같이 코드를 작성할 수 있습니다.
5) 세그트리 노드정보 업데이트
수를 변경할 때는 아래 정보를 이용하여 업데이트 할 수 있다.
-
노드가 담당하는 정보구간 (s-e)
- 바뀌는 노드의 위치(index)
- 바뀌는 노드의 값(value)
이때 세그트리를 탐색하며 나타나는 경우는
- s와 e를 포함하여 s-e 사이에 노드가 위치한 경우.
- 1이외에 경우, 포함하지 않는 경우.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | typedef int type; vector<type> input; vector<type> seg; const INF = 987654321; type mn2(type a, type b){ return (a > b)? b : a; } // 최소값을 return // s-e : 노드정보구간 // l-r : 찾을정보구간 void update(int node, int s, int e, int index, int value){ if(index < s || e < index) return ; // 2 seg[node] = mn2(seg[node], value); // update if(s != e){ // 1 update(2*node, s, (s+e)/2, index, value); update(2*node + 1, (s+e)/2 + 1, e, index, value); } } | cs |
위와 같이 작성할 수 있다.
'PSNote > Algorithm' 카테고리의 다른 글
버블정렬(Bubble Sort) (0) | 2017.11.18 |
---|---|
네트워크플로우, 에드몬드 카프(Edmonds-Karp) 알고리즘 (0) | 2017.11.15 |
SCC-코사라주 알고리즘(Kosaraju's Algorithm) (2) | 2017.07.23 |
강한연결요소(SCC ; Strongly Connected Component) (0) | 2017.07.22 |
펜윅트리(fenwick tree), 바이너리인덱스트리(BIT ; Binary Indexed Tree) (0) | 2017.07.18 |