본문 바로가기

알고리즘/개념

구간 트리(세그먼트 트리)

반응형

세그먼트 트리

 

저장된 자료들을 적절히 전처리해 그들에 대한 질의들을 빠르게 답할 수 있도록 하는 방법이다.

구간 트리의 기본적인 아이디어는 주어진 배열의 구간들을 표현하는 이진트리를 만드는 것이다.

구간 트리의 루트는 항상 배열의 [0,n-1]을 표현한다.

구간 트리

구간 트리에서 질의에 응답하는 시간복잡도는 O(logn)이다.

 

구간 트리에서 구간을 모두 저장하기 위한 배열의 길이는 n이 2의 거듭제곱이라면 2n이면 된다. 그렇지 않다면 가장 가까운 2의 거듭제곱으로 n을 올림한 뒤 2를 곱해야 한다. 

하지만 간단한 방법으로 4n으로 배열의 길이를 잡으면 된다. 메모리가 낭비된다는 단점이 있지만 편리하게 쓸 수 있다.

 

 

 

구간 트리 초기화

 

static long init(int node, int s, int e) {
	if(s==e)
		return tree[node]=arr[s];
	int mid = (s+e)/2;
	return tree[node]=init(node*2,s,mid)+init(node*2+1,mid+1,e);
}

 

예시로 구간 합을 위해 구간 트리를 초기화 하는 것을 보여준다.

구간 트리의 배열의 시작을 1부터 하여 왼쪽 자식의 인덱스가 node*2, 오른쪽 자식의 인덱스가 node*2+1이 될 수 있도록 한다.

s==e 지점은 트리의 리프 노드에 해당한다.

그 이외의 지점에는 왼쪽 자식과 오른쪽 자식의 합을 저장한다.

 

 

구간 트리 질의 응답

 

static long sum(int L, long R, int node, int nodeL, int nodeR) {
	if(nodeL > R || nodeR < L) return 0;
	if(L <= nodeL && nodeR <= R) return tree[node];
	int mid = (nodeL+nodeR)/2;
	return sum(L,R,node*2,nodeL,mid)+sum(L,R,node*2+1,mid+1,nodeR);
}

 

L부터 R까지의 범위 의 합을 구하는 함수이다.

만약 탐색하는 구간이 구하고자 하는 범위와 상관이 없으면 0을 리턴한다.

탐색하는 구간이 원하는 구간이라면 구간 트리에 저장되어 있는 값을 리턴한다.

그 외의 범위는 왼쪽 자식, 오른쪽 자식에서 찾은 값을 더해서 리턴한다.

 

 

구간 트리 갱신

 

static long update(int i, long val, int node, int s, int e) {
	if(i < s || e < i) return tree[node];
	if(s == e) {
		return tree[node] = val;
	}
	int mid = (s+e)/2;
	return tree[node] = update(node*2,i,val,s,mid)+update(node*2+1,i,val,mid+1,e);
}

 

i번째 값을 val로 바꾸는 작업을 하는 함수이다.

s==e가 되는 지점은 리프 노드에 해당하므로 값을 val값을 현재 노드에 넣어준다.

그 외의 지점은 왼쪽 자식과 오른쪽 자식의 합으로 갱신해준다.

 

참고 문제

http://boj.kr/2042

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다. 그리고 N+2번째 줄부터 N+M+K+1번째 줄까지 세 개의 정수 a, b, c가 주어지는데, a가 1인 경우 b번째 수를 c로 바꾸고 a가 2인 경우에는 b번째 수부터 c번째 수까지의

www.acmicpc.net

http://boj.kr/11505

 

11505번: 구간 곱 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 곱을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다. 그리고 N+2번째 줄부터 N+M+K+1 번째 줄까지 세 개의 정수 a,b,c가 주어지는데, a가 1인 경우 b번째 수를 c로 바꾸고 a가 2인 경우에는 b부터 c까지의 곱을 구하여 출

www.acmicpc.net

 

 

'알고리즘 > 개념' 카테고리의 다른 글

투 포인터  (0) 2020.05.03
다익스트라,벨만포드,플로이드 워샬  (0) 2020.04.16
Permutation & Combination  (0) 2020.02.18
DISJOINT-SETS, MST  (0) 2020.02.14