-
๐ฒ Segment Tree 1 - Segment Tree๋?ALicademy ๐ฉ๐ซ๐จ๐ซ/์๊ณ ๋ฆฌ์ฆ 2020. 8. 31. 16:33
์๋ณธ์ ๋งํฌ๋ฅผ ํตํด ํ์ธํ์ค ์ ์์ต๋๋ค ๐
Intro ๐
์ค๋งํธํฐ์ ์ผ์ SNS๋ฅผ ๋ค์ด๊ฐ๋ด ์๋ค. ์ง๋ ํ ๋ฌ ๋์ ์ฌ๋ฌ๋ถ์ด ๋ฐ์ ์ข์์๐ ์ ํฉ์ ๊ตฌํ๊ณ ์ถ์ผ๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ๋ ๊น์?
์๋ง ์ฌ๋ฌ๋ถ์ด ์ ์ ๋น์ทํ๋ค๋ฉด ๊ฐ์ฅ ๋จผ์ '๋ชจ๋ ๊ฒ์๋ฌผ ์ค ์ง๋ ํ ๋ฌ ๋์์ ๊ฒ์๋ฌผ์์ ๋ฐ์ ์ข์์ ์๋ฅผ ์ผ์ผ์ด ๋ํ๋ฉด ๋์ง ์์๊น์?' ๋ผ๊ณ ๋ง์ํ์ค์ง๋ ๋ชจ๋ฆ ๋๋ค.
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ ๋ ๊ฒ์๋ฌผ์ ์๊ฐ $n$๊ฐ์ด๊ณ ํน์ ๊ธฐ๊ฐ ๋์ ๋ฐ์ ์ข์์ ์์ ํฉ์ ๋ฌป๋ query๋ฅผ $m$๊ฐ ์ฒ๋ฆฌํด์ผ ํ๋ค๋ฉด ์๊ฐ ๋ณต์ก๋๋ $O(mn)$์ ๋๋ค. ์ด ๋ฐฉ๋ฒ๋ ๋์์ง ์์ง๋ง ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์์๊น์?
๊ทธ๋์ ์ค๋ ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ธ ๊ฒ์ ๋ฐ๋ก ๊ตฌ๊ฐ์ ํฉ/ ์ฐจ/ ์ต๋๊ฐ/ ์ต์๊ฐ ๋ฑ์ ํจ์จ์ ์ผ๋ก ๊ตฌํ๊ธฐ ์ํด ์ฐ์ด๋ ์๋ฃ ๊ตฌ์กฐ์ธ
๐ดSegment Tree๐ด์ ๋๋ค.
Segment Tree ๐ด
Segment Tree๋ ๊ฐ ๋ ธ๋๊ฐ ๊ตฌ๊ฐ์ ๋ํ๋ด๋ binary tree์ ๋๋ค. ๊ฐ ๋ ธ๋๋ ๋์ค์ query์์ ์๊ตฌํ๋ ๊ฐ ์ฆ, ๋ํ๊ฐ์ ์ ์ฅํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด segment tree๋ ์ด๋ป๊ฒ ๋ง๋ค ์ ์์๊น์? ๐ค
๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ์๋ ๊ธธ์ด๊ฐ $n$์ธ ๋ฐฐ์ด arr์ด ์๋ค๊ณ ๊ฐ์ ํ ๋ arr๋ก๋ถํฐ segment tree๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
-
Segment tree์ root๋ ๋ชจ๋ ๊ตฌ๊ฐ ์ฆ, $arr[0 : n - 1]$์์ ์ฐ๋ฆฌ๊ฐ ๊ด์ฌ์ ๊ฐ์ง๋ data๋ฅผ ๋ํ๋ ๋๋ค.
-
Segment tree์ ๊ฐ leaf node๋ ํ๋์ element๊ฐ ๊ฐ์ง๋ ๋ฒ์๋ฅผ ๋ํ๋ ๋๋ค. ๋ค์ ๋งํด $arr[0]$๋ถํฐ $arr[n - 1]$ ๊น์ง ๋ชจ๋ leaf node์ ์์นํฉ๋๋ค.
-
internal node๋ ์์ ๋ ธ๋ ๊ฒฐ๊ณผ๋ค์ ์ข ํฉํ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ ๋๋ค. ๋ค์ ๋งํด ๋ ธ๋์ ๋ํ๊ฐ์ด ์ต๋๊ฐ์ด๋ผ๋ฉด internal node๋ ์์ ๋ ธ๋๋ค ์ค ์ต๋๊ฐ์ ์์ ์ ๊ฐ์ผ๋ก ๊ฐ์ง๋๋ค.
-
๊ฐ ์๋ ๋ ธ๋๋ค์ ๋ถ๋ชจ ๋ ธ๋๊ฐ ๋ํ๋ด๋ ๋ฒ์์ ๋๋ต์ ์ผ๋ก ์ ๋ฐ์ ๋ํ๋ ๋๋ค.
-
$n$๊ฐ์ element๋ฅผ ๋ํ๋ด๊ธฐ ์ํ segment tree๋ ํธํ๊ฒ $4n$์ ํฌ๊ธฐ๋ก ๋ํ๋ผ ์ ์์ต๋๋ค. (์์ธํ ์ค๋ช ์ ๋งํฌ ๊ฑธ๋ฆฐ Stack overflow๋ฅผ ํ์ธํด์ฃผ์ธ์.)
-
Segment tree์ root์ index๊ฐ 1์ผ ๋ ํ ๋ ธ๋์ index๊ฐ $i$ ๋ผ๋ฉด ์์ ๋ ธ๋๋ค์ index๋ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ ๊ฐ๊ฐ $(2i), (2i + 1)$์ ๋๋ค. (root์ index๊ฐ 0์ผ๋๋ ์ด๋ป๊ฒ ๋ ๊น์? ์ฌ๋ฌ๋ถ๊ป์ ํ ๋ฒ ํด๊ฒฐํด๋ณด์ธ์! ๐จ๐ซ)
์ง๊ธ๋ถํฐ๋ ๋ณธ๊ฒฉ์ ์ผ๋ก segment tree๋ฅผ buildํ๊ณ updateํ๋ ๋ฐฉ๋ฒ, query๋ฅผ ๊ตฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์๋ ค๋๋ฆด ๊ฑด๋ฐ ์ดํด๋ฅผ ๋๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ํ๊ฐ์ด ๊ตฌ๊ฐ์์์ ํฉ์ธ segment tree๋ฅผ ์๋ก ๋ค๊ฒ ์ต๋๋ค.
Build
segment tree๋ ์์ ์ธ๊ธํ ๋ช ๊ฐ์ง ์ฑ์ง๊ณผ recursion๋ง ์ด์ฉํ๋ฉด ์ง๊ด์ ์ด๊ณ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. segment tree๋ฅผ recursiveํ๊ฒ ๋ง๋ค ๋๋ bottom up ๋ฐฉ์์ผ๋ก ๋ง๋ค์ด์ง๋๋ค. ๋ค์์ segment tree๋ฅผ buildํ๋ ์ฝ๋์ ๋๋ค.
Update
๋ง์ฝ ๋ฐฐ์ด arr์ 2๋ฒ์งธ index๊ฐ์ 5๋ก ๋ฐ๊พธ๋ฉด ์ด๋ป๊ฒ segment tree๋ ์ด๋ป๊ฒ ๋ฐ๋๊น์?
segment tree์ ๋ ธ๋๋ค ์ค 2๋ฒ์งธ index๋ผ๋ ๊ตฌ๊ฐ์ ํฌํจํ๋ ๋ชจ๋ ๋ ธ๋๋ค์ ์์ ๋์ด์ผ ํ ๊ฒ์ ๋๋ค.
๋ค์์ arr์ 2๋ฒ์งธ index๊ฐ์ 5๋ก ๋ฐ๊พธ์์๋ ์ํฅ์ ๋ฐ๋ ๋ ธ๋๋ค์ ๋นจ๊ฐ์ ํ ๋๋ฆฌ๋ก ํ์ํ ๊ฒ์ ๋๋ค.
leaf node๊ฐ ์์ ๋๋ฉด ๊ทธ ๋ ธ๋๋ฅผ ์์์ผ๋ก ๊ฐ๋ ๋ถ๋ชจ ๋ ธ๋, ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ถ๋ชจ์ ๋ถ๋ชจ ๋ ธ๋๋ค ๋ชจ๋ ์ํฅ์ ๋ฐ์ต๋๋ค.
์ด๊ฑธ ๋ณด๋ Bottom up ๋ฐฉ์์ด ์๊ฐ๋๊ณ Bottom up ๋ฐฉ์์ ์๊ฐํ๋ ์ฐ๋ฆฌ๊ฐ ๋ฐฉ๊ธ ์ดํด๋ณธ build ๊ณผ์ ์ด ์๊ฐ๋์ง ์์ผ์๋์?
๋ง์ฝ ๊ทธ๋ฌ์๋ค๋ฉด ์ฌ๋ฌ๋ถ๊ป ๋ฐ์๋ฅผ ๋ณด๋ด๋๋ฆฌ๊ณ ์ถ์ต๋๋ค! ์ ๋ง ๋๋จํ์ญ๋๋ค! ๐๐๐
์ค์ ๋ก update๋ฅผ ํ๋ ๊ณผ์ ์ buildํ๋ ๊ณผ์ ๊ณผ ๋งค์ฐ ์ ์ฌํฉ๋๋ค! ๋ค์์ ๊ด๋ จ ์ฝ๋์ ๋๋ค.
Query
๋ง์ฝ segment tree๋ฅผ ์ด์ฉํด arr์ 2๋ฒ์งธ๋ถํฐ 4๋ฒ์งธ index ๊ฐ์ ํฉ์ ๊ตฌํ๋ ค๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ๋ ๊น์?
segment tree์ ๋ ธ๋๊ฐ ๋ํ๋ด๋ ๋ฒ์๊ฐ 2๋ฒ์งธ๋ถํฐ 4๋ฒ์งธ ์ธ๋ฑ์ค์ ์ํ๋ฉด ๊ทธ ๊ฐ์ returnํด์ ๋ํ๋ฉด ์ด๋จ๊น์?
์ฆ, ๋ค์๊ณผ ๊ฐ์ด ๋ณด๋ผ์์ผ๋ก ์น ํ ๋ ธ๋๋ค์ด 2๋ฒ์งธ๋ถํฐ 4๋ฒ์งธ ์ธ๋ฑ์ค์ ์ํ๊ธฐ ๋๋ฌธ์ ์ด ๊ฐ๋ค์ returnํด์ ๋ํ๋ ๊ฒ๋๋ค! ๐
Divide & Conquer ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ๋ฐฉ์์ด ์ ๋ง ์๋ฆ๋ต์ง ์๋์? โจโจโจ
๊ฐ์ธ์ ์ผ๋ก segment tree์ ์๋ฆ๋ค์์ ์ฌ๊ธฐ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค!
๊ด๋ จ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค!
Complexity Analysis
๋งจ ์ฒ์ segment tree๋ ๊ตฌ๊ฐ์ ํฉ/ ์ฐจ/ ์ต๋๊ฐ/ ์ต์๊ฐ ๋ฑ์ ํจ์จ์ ์ผ๋ก ๊ตฌํ๊ธฐ ์ํด ์ฐ์ด๋ ์๋ฃ ๊ตฌ์กฐ๋ผ๊ณ ํ๋๋ฐ ๊ณผ์ฐ ์ผ๋ง๋ ํจ์จ์ ์ผ๊น์? ์๊ฐ ๋ณต์ก๋๋ฅผ ํตํด ์์๋ด ์๋ค!
Build
segment tree๋ฅผ buildํ๋ ๊ณผ์ ์ ์ดํด๋ด ์๋ค. ์๋ ๋ฐ์ดํฐ์ ๊ธธ์ด๊ฐ $n$์ด๋ผ๋ฉด segment tree์ ๋ ธ๋๋ ๋๋ต์ ์ผ๋ก $2n$๊ฐ ์ ๋๋ค.
์๋ํ๋ฉด setment tree์ leaf node์๋ ์๋ ๋ฐ์ดํฐ์ element๋ค์ด ๋ค์ด๊ฐ๊ธฐ ๋๋ฌธ์ leaf node์ ๊ฐ์๊ฐ $n$๊ฐ์ด๊ณ leaf node์ ๋ถ๋ชจ ๋ ธ๋๋ $\frac{n}{2}$๊ฐ ์ด๊ธฐ ๋๋ฌธ์ $n + \frac{n}{2} + \frac{n}{4} + ... + 1 \approx 2n$ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ทธ๋์ segment tree๋ฅผ buildํ๊ธฐ ์ํด์๋ ์ฝ $2n$๊ฐ์ ๋ ธ๋๋ฅผ ๋ชจ๋ ๋ฐฉ๋ฌธํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์๊ฐ ๋ณต์ก๋๋ $O(n)$์ ๋๋ค!
Update
updateํ๋ ๊ณผ์ ์ ๋ณด์๋ฉด ์์๋ค์ํผ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋ ์ค updateํ ๋ ธ๋๊ฐ ์๋ ์ชฝ์ผ๋ก ์ด๋ํฉ๋๋ค.
์ ์๊ฐํด๋ณด๋ฉด ์ฐ๋ฆฐ ์ด๊ฒ์ด binary search์ ์ ์ฌํ๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๊ทธ๋์ binary search์ ๋ง์ฐฌ๊ฐ์ง๋ก update ๊ณผ์ ๋ ์๊ฐ ๋ณต์ก๋๊ฐ $O(\log{N})$ ์ ๋๋ค.
Query
query๋ฅผ ๊ตฌํ๋ ๊ณผ์ ์ ์ผ๋ง๋ ๊ฑธ๋ฆด๊น์?
๋ฏธ๋ฆฌ ๋ง์๋๋ฆฌ๋ฉด query๋ฅผ ๊ตฌํ๋ ๊ณผ์ ์ ์๊ฐ ๋ณต์ก๋๊ฐ $O(log{N})$ ์ ๋๋ค. ๊ทธ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
query๋ฅผ ๊ตฌํ๊ธฐ ์ํด์๋ query์์ ์๊ตฌํ๋ ๊ตฌ๊ฐ์ ์ ํํ ์ผ์นํ๋ ๋ ธ๋๋ค์ DFS๋ฅผ ํตํด ์ฐพ์์ผ ํฉ๋๋ค.
์ต์ ์ ๊ฒฝ์ฐ segment tree์ leaf node๊น์ง ๋ฐฉ๋ฌธํด์ผ ํ๋๋ฐ ์ด๋ segment tree์ ๋์ด์ธ $log{N}$ ๊ณผ ๋์ผํฉ๋๋ค. ๋ฐ๋ผ์ query๋ฅผ ๊ตฌํ๋ ๊ณผ์ ์ ์๊ฐ ๋ณต์ก๋๋ $O(log{N})$ ์ ๋๋ค!
Let's do PS ๐
Segment Tree๊ฐ ์ ์ดํด๋์ จ๋์?
๊ทธ๋ ๋ค๋ฉด ํจ๊ป BOJ 2042๋ฒ ๊ตฌ๊ฐ ํฉ ๊ตฌํ๊ธฐ 1์ ํ์ด๋ด ์๋ค!
๋์์ด ํ์ํ์ค ๋ ์ฐธ๊ณ ํด์ฃผ์ธ์!
๋๋ณด๊ธฐimport java.io.BufferedReader; import java.io.InputStreamReader; public class BOJ_2042 { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] inputs = br.readLine().split(" "); int N = Integer.parseInt(inputs[0]); int M = Integer.parseInt(inputs[1]); int K = Integer.parseInt(inputs[2]); long[] arr = new long[N + 1]; long[] tree = new long[4 * N]; for(int i = 1; i <= N; i++) { arr[i] = Integer.parseInt(br.readLine()); } // build build(tree, arr, 1, N, 1); for(int i = 0; i < M + K; i++) { inputs = br.readLine().split(" "); int a = Integer.parseInt(inputs[0]); long b = (long) Double.parseDouble(inputs[1]); long c = (long) Double.parseDouble(inputs[2]); switch(a) { case 1 : //update update(tree, b, c, 1, N, 1); break; case 2 : // query System.out.println(query(tree, (int) b, (int) c, 1, N, 1)); break; } } } public static void build(long[] tree, long[] arr, int lo, int hi, int idx) { if(lo == hi) { tree[idx] = arr[lo]; return; } int mid = lo + (hi - lo) / 2; build(tree, arr, lo, mid, 2 * idx); build(tree, arr, mid + 1, hi, 2 * idx + 1); tree[idx] = tree[2 * idx] + tree[2 * idx + 1]; } public static void update(long[] tree, long target, long value, int lo, int hi, int idx) { if(lo == hi) { tree[idx] = value; return; } int mid = lo + (hi - lo) / 2; if(mid >= target) { update(tree, target, value, lo, mid, 2 * idx); } else { update(tree, target, value, mid + 1, hi, 2 * idx + 1); } tree[idx] = tree[2 * idx] + tree[2 * idx + 1]; } public static long query(long[] tree, int from, int to, int lo, int hi, int idx) { if(from > hi || to < lo) return 0; if(from <= lo && hi <= to) return tree[idx]; int mid = lo + (hi - lo) / 2; return query(tree, from, to, lo, mid, 2 * idx) + query(tree, from, to, mid + 1, hi, 2 * idx + 1); } }
Further Thinking ๐ค
๋ง์ฝ ํน์ ์ธ๋ฑ์ค๊ฐ ์๋๋ผ ํน์ ๊ตฌ๊ฐ์ updateํ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์?
๋ฌผ๋ก ์ฐ๋ฆฌ๊ฐ ์์ ์์ฑํ ์ฝ๋๋ฅผ ์ด์ฉํด๋ ๋ฉ๋๋ค. ํ์ง๋ง ๊ทธ๋ด ๊ฒฝ์ฐ ๋ฐ๋ณต์ ์ผ๋ก ๋ฐฉ๋ฌธํ๋ ๋ ธ๋๊ฐ ์๊ธธ ์ ์์ต๋๋ค.
arr์ 1๋ฒ์งธ๋ถํฐ 2๋ฒ์งธ ์ธ๋ฑ์ค์ ๊ฐ์ 1์ฉ ์ฆ๊ฐํ๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค.
1๋ฒ์งธ ์ธ๋ฑ์ค๋ฅผ updateํ ๋๋ 1 → 2 → 4 → 9 ์์๋ก ๋ ธ๋๋ฅผ ๋ฐฉ๋ฌธํด์ผ ํฉ๋๋ค.
2๋ฒ์งธ ์ธ๋ฑ์ค๋ฅผ updateํ ๋๋ 1 → 2→ 5 ์์๋ก ๋ฐฉ๋ฌธํด์ผ ํฉ๋๋ค.
์ด๋ ์ฐ๋ฆฌ๋ 1, 2๋ฒ ๋ ธ๋๋ ๋ ๋ฒ ๋ฐฉ๋ฌธํ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์ด๋ค ๋ ๋ฒจ์์๋ ๋ค๋ฅธ leaf nodef๋ก '์ ๋ฌ'๋๋ ๋ณํ๋ค์ด ์๋ก ๋ง๋๊ธฐ ๋๋ฌธ์ ๋๋ค. update๋๋ query๊ฐ ์ ๋ง ๋ง์ ๊ฒฝ์ฐ ์ฐ๋ฆฌ๋ updateํ๊ธฐ ์ํด ๋ง์ ์๊ฐ์ ํ๋นํ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๊น์? ๋ต์ ๋ค์ ์๊ฐ์ ๋ฐฐ์ธ 'Lazy propagation'์ ์์ต๋๋ค.
๊ทธ๋ผ ๋ค์ ์๊ฐ์ ๋ต๊ฒ ์ต๋๋ค. ๊ฐ์ฌํฉ๋๋ค ๐ค
์ฐธ๊ณ
https://bowbowbow.tistory.com/4
https://medium.com/@sivagiri/dissecting-into-segment-trees-ee603a4740d3
https://en.wikipedia.org/wiki/Segment_tree
'ALicademy ๐ฉโ๐ซ๐จโ๐ซ > ์๊ณ ๋ฆฌ์ฆ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ ํด๋ฆฌ๋ ์๊ณ ๋ฆฌ์ฆ - ๋ ์์ ์ต๋๊ณต์ฝ์๋?๐คจ (0) 2021.07.04 ๐ฒ Segment Tree 2 - ๋ ๋น ๋ฅธ update๋ฅผ ์ํ Lazy Propagation! (0) 2020.09.01 -