๊ตฌ๊ฐ ํธ๋ฆฌ(Segment Tree)
์ผ์ฐจ์ ๋ฐฐ์ด์ ํน์ ๊ตฌ๊ฐ์ ๋ํ ์ง๋ฌธ์ ๋น ๋ฅด๊ฒ ๋๋ตํ๋ ๋ฐ ํ์ฉ๋๋ ์๋ฃ๊ตฌ์กฐ
๋ํ์ ์ผ๋ก ๊ตฌ๊ฐ ์์๋ค์ ํฉ, ๊ตฌ๊ฐ ์์๋ค์ ์ต์๊ฐ(RMQ, Range Minimum Query) ๋ฑ์ ๋ํ ์ง์๋ฅผ ์ง์ํ๋ค.
๊ตฌ๊ฐ ํธ๋ฆฌ ์ด๊ธฐํ
- ๋ฐฐ์ด์ ๊ฐ ๊ตฌ๊ฐ์ ํํํ๋ ์ด์ง ํธ๋ฆฌ ํํ
- ๊ตฌ๊ฐ ํธ๋ฆฌ์ ๋ฃจํธ๋ ๋ฐฐ์ด์ ์ ์ฒด ๊ตฌ๊ฐ(
[0, n-1
)์ ํํ - ๊ฐ ํธ๋ฆฌ(i)์ ์ผ์ชฝ ์์(2i)๊ณผ ์ค๋ฅธ์ชฝ ์์(2i+1)์ ํด๋น ๊ตฌ๊ฐ์ ๋ฐ์ผ๋ก ๋๋ ์ผ์ชฝ ๋ถ๋ถ์ ์ค๋ฅธ์ชฝ ๋ถ๋ถ์ ํํ
- ๋ฆฌํ ๋ ธ๋๋ ๊ตฌ๊ฐ์ ํฌ๊ธฐ๊ฐ 1์ธ ๊ฒฝ์ฐ
- ์ ์ฒด ๊ตฌ๊ฐ ํฌ๊ธฐ๊ฐ 2์ ์ ๊ณฑ๊ผด์ด๋ผ๋ฉด ๋
ธ๋๊ฐ
2*(h+1)-1
๊ฐ์ธ ์์ ์ด์ง ํธ๋ฆฌ๊ฐ ์์ฑ๋๊ฒ ์ง๋ง, 2์ ์ ๊ณฑ๊ผด์ด ์๋๋๋ผ๋ ๋จ๋ ๋ ธ๋๋ ๋น ๊ณต๊ฐ์ผ๋ก ๋จ๊ฒจ๋๊ณ2*(h+1)-1
ํฌ๊ธฐ์ ๋ฐฐ์ด๋ก ํํํ๋ ๊ฒ์ด ํธํจ. - ๊ตฌ๊ฐ ํธ๋ฆฌ์ ๊ฐ ๋ ธ๋๋ ํด๋นํ๋ ๊ตฌ๊ฐ์ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํด๋๋ค. ๋ฐ๋ผ์ ์ต์ ๊ตฌ๊ฐ ๋ฌธ์ ์ ๊ฒฝ์ฐ ๊ฐ ๊ตฌ๊ฐ์ ์ต์๊ฐ์, ๊ตฌ๊ฐ์ ํฉ ๋ฌธ์ ์ ๊ฒฝ์ฐ ๊ฐ ๊ตฌ๊ฐ์ ์์๋ค์ ํฉ์ ๋ ธ๋์ ์ ์ฅํด๋๋ค.
- ์ด๋ค ๊ตฌ๊ฐ์ด ์ฃผ์ด์ง๋๋ผ๋ ํด๋น ๊ตฌ๊ฐ์ ๊ตฌ๊ฐํธ๋ฆฌ ๋ ธ๋์ ํฌํจ๋ ๊ตฌ๊ฐ๋ค์ ํฉ์งํฉ์ผ๋ก ํํํ ์ ์๋ค.
๊ตฌ๊ฐ ํธ๋ฆฌ ์ง์
๊ตฌ๊ฐ ํธ๋ฆฌ๋ก ํด๊ฒฐํ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ๋ฌธ์ ์ธ ๊ตฌ๊ฐ ์ต์ ๋ฌธ์ (RMQ, Range Minimum Query)๋ฅผ ๋ณด์.
์๋ฆฌ
์ํ๋ ๊ตฌ๊ฐ์ ํฌํจํ๋ ๊ตฌ๊ฐ ์งํฉ ์ค ์งํฉ์ ํฌ๊ธฐ๊ฐ ์ต์์ธ ๊ตฌ๊ฐ์ ์ฐพ๋๋ค.
- ๋ง์ฝ ํ์ฌ ๊ตฌ๊ฐ์ด ์ํ๋ ๊ตฌ๊ฐ์ ์ ํ ํฌํจํ์ง ์๋๋ค๋ฉด ๋ฌดํ๋๋ฅผ ๋ฐํํ๋ค.
- ๋ง์ฝ ํ์ฌ ๊ตฌ๊ฐ์ด ์ํ๋ ๊ตฌ๊ฐ์ ์์ ํ ํฌํจ๋๋ค๋ฉด ํ์ฌ ๋ ธ๋(๊ตฌ๊ฐ์ ์ต์๊ฐ์ ์ ์ฅํ ์ํ)๋ฅผ ๋ฐํํ๋ค.
- ์์ ๋ ๊ฒฝ์ฐ๊ฐ ์๋ ๊ฒฝ์ฐ(์ฆ, ํ์ฌ ๊ตฌ๊ฐ์ด ์ํ๋ ๊ตฌ๊ฐ์ ํฌํจํ๋ ์ ๋ถ๋ฅผ ํฌํจํ์ง ์๊ฑฐ๋ ์๋๋ฉด ์ต์ ํฌ๊ธฐ๊ฐ ๋ณด์ฅ๋์ง ์์ ๊ฒฝ์ฐ)์๋ ํ์ฌ ๊ตฌ๊ฐ์ ๋ฐ์ผ๋ก ๋๋ ์์ ๊ณผ์ ์ ๋ค์ ๋ฐ๋ณตํ๊ณ ๋ ๋ค ๊ฒฐ๊ณผ ์ค ์ต์๊ฐ์ ๋ฐํํ๋ค.
์๊ฐ ๋ณต์ก๋
๊ตฌ๊ฐ ํธ๋ฆฌ์ ๋ ๋ฒจ์ O(log n)
์ด๋ฉฐ ์ง์๋ฅผ ์ํด ์ต๋ ๊ตฌ๊ฐ ํธ๋ฆฌ์ ๋ ๋ฒจ ๋งํผ ํ์ธํ๋ฉด ๋๋ฏ๋ก O(log n)
์ ์ฐ์ฐ์ด ํ์ํ๋ค.
๊ตฌํ
class SegmentTreeRMQ
{
static int sTree[]; // ์ธ๊ทธ๋จผํธ ํธ๋ฆฌ
// ๋ ๊ฐ์ ๋น๊ตํด ๋ ์์ ๊ฐ์ ๋ฐํํ๋ ํจ์
static int minVal(int x, int y) {
return (x < y) ? x : y;
}
// ๊ตฌ๊ฐ์ ์ค๊ฐ ์์น๋ฅผ ์ธ๋ฑ์ค๋ก ๊ตฌํ๋ ํจ์
static int getMid(int s, int e) {
return (s + e) / 2;
}
// ์ฃผ์ด์ง ๋ฐฐ์ด(์ ์ฒด ๊ตฌ๊ฐ)์ ๋ง๋ ์์ ์ด์ง ํธ๋ฆฌ ๋ง๋ค๊ธฐ
static void treeInit(int arr[], int n) {
// ํธ๋ฆฌ์ ๋์ด
int x = (int) (Math.ceil(Math.log(n) / Math.log(2)));
// ํธ๋ฆฌ ์ต๋ ํฌ๊ธฐ (์ด๋ ๊ฒ ์ง์ ๊ณ์ฐํ์ง ์๊ณ n*4๋ฅผ ํ๊ฒ๋๋ฉด ์ฝ๊ฒ ๋ชจ๋ ๋ฐฐ์ด ์์๋ฅผ ํฌํจํ๋ ํธ๋ฆฌ๋ฅผ ๋ง๋ค ์ ์์ง๋ง ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๊ฐ ๋ฐ์ํ ์ ์์)
int max_size = 2 * (int) Math.pow(2, x) - 1;
sTree = new int[max_size];
// ์์ฑํ ํธ๋ฆฌ์ ๋ฐฐ์ด์ ์์ ์ฝ์
nodeInit(arr, 0, n-1, 1);
}
// ์ธ๊ทธ๋จผํธ ํธ๋ฆฌ ์ด๊ธฐํ(๊ฐ ๋
ธ๋์ ๊ฐ ๊ตฌ๊ฐ์ ์ต์๊ฐ์ ์ ์ฅ)
static int nodeInit(int arr[], int arrStart, int arrEnd, int node) {
// ๋ฆฌํ๋
ธ๋ ํน์ ์์ ๋
ธ๋๋ค์ด ์ด๋ฏธ ๊ฐ์ ๊ตฌ๊ฐ์ ์ต์๊ฐ์ ๊ณ์ฐํ์ฌ ์ ์ฅํ๊ณ ์๋ ๊ฒฝ์ฐ
if (arrStart == arrEnd) return sTree[node] = arr[arrStart];
// ๊ตฌ๊ฐ์ ๋ฐ์ผ๋ก ๋๋ ๊ฐ๋ฉฐ ์ฌ๊ท์ ์ผ๋ก ์์ ๋
ธ๋๋ค์ ๊ฐ ๋
ธ๋๊ฐ ํฌํจํ๋ ๊ตฌ๊ฐ์ ์ต์๊ฐ์ ์ ์ฅ
int mid = getMid(arrStart, arrEnd);
return sTree[node] = minVal(nodeInit(arr, arrStart, mid, 2*node), nodeInit(arr, mid+1, arrEnd, 2*node+1));
}
// ๊ตฌ๊ฐ ์ต์๋ฅผ ๊ตฌํ๋ ๋ฉ์๋
static int RMQ(int treeStart, int treeEnd, int queryStart, int queryEnd, int node) {
// ํ์ฌ ๋
ธ๋์ ํํ๋ ๊ตฌ๊ฐ์ด ํ์์ ์ํ๋ ๊ตฌ๊ฐ์ ์์ ํ ๋ฐฐ์ ํ๋ค๋ฉด ๋ฌดํ๋ ๋ฐํ
if (treeStart > queryEnd || treeEnd < queryStart) return Integer.MAX_VALUE;
// ํ์ฌ ๋
ธ๋์ ํํ๋ ๊ตฌ๊ฐ์ด ํ์์ ์ํ๋ ๊ตฌ๊ฐ์ ํฌํจ๋๋ค๋ฉด ๋
ธ๋(๊ตฌ๊ฐ์ ์ต์๊ฐ)์ ์ ์ฅ๋ ๊ฐ ๋ฐํ
if (queryStart <= treeStart && queryEnd >= treeEnd) return sTree[node];
// ํ์ฌ ๋
ธ๋์ ํํ๋ ๊ตฌ๊ฐ์ด ํ์์ ์ํ๋ ๊ตฌ๊ฐ์ ์ผ๋ถ ํฌํจํ ๊ฒฝ์ฐ ํ์ฌ ๊ตฌ๊ฐ์ ์ผ์ชฝ ๋ถ๋ถ์ ์ค๋ฅธ์ชฝ ๋ถ๋ถ์ผ๋ก ๋๋ ๋ค์ ์ง์
int mid = getMid(treeStart, treeEnd); // ํ์ฌ ๋
ธ๋์ ๊ตฌ๊ฐ์ ๋๋
// ์ผ์ชฝ ๊ตฌ๊ฐ์ ๋ํด ์ง์ํ ๊ฒฐ๊ณผ์ ์ค๋ฅธ์ชพ ๊ตฌ๊ฐ์ ๋ํด ์ง์ํ ๊ฒฐ๊ณผ ์ค ์ต์๊ฐ์ ์ฑํ
return minVal(RMQ(treeStart, mid, queryStart, queryEnd, 2*node), RMQ(mid+1, treeEnd, queryStart, queryEnd, 2*node+1));
}
public static void main(String args[]) {
int arr[] = {1, 3, 2, 7, 9, 11};
// ์ฃผ์ด์ง ๋ฐฐ์ด์ ๋ง๋ ํธ๋ฆฌ ์์ฑ
treeInit(arr, arr.length);
int queryStart = 2; // ํ์ ์ํ๋ ๊ตฌ๊ฐ ์์ ์ง์
int queryEnd = 3; // ํ์ ์ํ๋ ๊ตฌ๊ฐ ์ข
๋ฃ ์ง์
System.out.println(
"Minimum of values in range [" + queryStart + ", " + queryEnd + "] is = " + RMQ(0, arr.length-1, queryStart, queryEnd, 1));
}
}
๋ง์ฝ ๊ตฌ๊ฐ ํฉ์ ๊ตฌํ๋ ๋ฌธ์ ๋ก ๋ฐ๊พธ์ด ํ๊ณ ์ถ๋ค๋ฉด
nodeInit()
๋ฉ์๋์์ ๊ฐ ๋ ธ๋์ ๊ตฌ๊ฐ์ ์ต์๊ฐ์ ์ ์ฅํ์ง ๋ง๊ณ ๊ตฌ๊ฐํฉ์ ๊ณ์ฐํด์ ์ ์ฅํ๋ฉด ๋๋ค.
public class SegmentTreeSum {
static int N, M, K;
static long[] sTree, arr;
public static long initNode(int start, int end, int node) {
if(start == end) return sTree[node] = arr[start];
int mid = (start + end)/2;
return sTree[node] = initNode(start, mid, node*2)
+ initNode(mid+1, end, node*2+1);
}
public static long sum(int tStart, int tEnd, int qStart, long qEnd, int node) {
if (qEnd<tStart || qStart>tEnd) return 0;
if (qStart<=tStart && qEnd>=tEnd) return sTree[node];
int mid = (tStart+tEnd)/2;
return sum(tStart, mid, qStart, qEnd, 2*node)
+ sum(mid+1, tEnd, qStart, qEnd, 2*node+1);
}
public static void update(int start, int end, int node, int idx, long value) {
if (idx<start || idx>end) return;
sTree[node] += value;
if (start==end) return;
int mid = (start+end)/2;
update(start, mid, 2*node, idx, value);
update(mid+1, end, 2*node+1, idx, value);
}
}
๊ตฌ๊ฐ ํธ๋ฆฌ ๊ฐฑ์
๊ตฌ๊ฐ ํธ๋ฆฌ ์ด๊ธฐํ ๋จ๊ณ์์ ์ฃผ์ด์ง ๋ฐฐ์ด๋๋ก ํธ๋ฆฌ๋ฅผ ๋ง๋ค์๋ค. ํ์ง๋ง ์ดํ ๋ฐฐ์ด์ ์์๋ฅผ ๋ฐ๊พธ์ด ํธ๋ฆฌ์ ๋ค์ ๋ฐ์ํด์ผํ ์ ์๋ค. ๊ตฌ๊ฐ ํธ๋ฆฌ๋ฅผ ๊ฐฑ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ณด์.
์๋ฆฌ
์ํ๋ ๊ตฌ๊ฐ์ ํฌํจํ๋ ๊ตฌ๊ฐ ์งํฉ ์ค ์งํฉ์ ํฌ๊ธฐ๊ฐ ์ต์์ธ ๊ตฌ๊ฐ์ ์ฐพ๋๋ค.
- ๋ง์ฝ ํ์ฌ ๊ตฌ๊ฐ์ด ์ํ๋ ๊ตฌ๊ฐ์ ์ ํ ํฌํจํ์ง ์๋๋ค๋ฉด pass
- ๋ง์ฝ ํ์ฌ ๊ตฌ๊ฐ์ด ์ํ๋ ๊ตฌ๊ฐ์ ์์ ํ ํฌํจ๋๋ค๋ฉด ํ์ฌ ๋ ธ๋์ ๊ฐ์ ๊ฐฑ์ ํ๋ค.
- ์์ ๋ ๊ฒฝ์ฐ๊ฐ ์๋ ๊ฒฝ์ฐ(์ฆ, ํ์ฌ ๊ตฌ๊ฐ์ด ์ํ๋ ๊ตฌ๊ฐ์ ํฌํจํ๋ ์ ๋ถ๋ฅผ ํฌํจํ์ง ์๊ฑฐ๋ ์๋๋ฉด ์ต์ ํฌ๊ธฐ๊ฐ ๋ณด์ฅ๋์ง ์์ ๊ฒฝ์ฐ)์๋ ํ์ฌ ๊ตฌ๊ฐ์ ๋ฐ์ผ๋ก ๋๋ ์์ ๊ณผ์ ์ ๋ค์ ๋ฐ๋ณตํ๋ฉฐ ๊ฐ์ ๊ฐฑ์ ํ๋ค.
์๊ฐ ๋ณต์ก๋
๋ณ๊ฒฝ์ ์ํ๋ ์์๋ฅผ ํฌํจํ๋ ๊ตฌ๊ฐ์ ๊ตฌ๊ฐ ํธ๋ฆฌ์ O(log n)
๊ฐ ์กด์ฌํ๋ฏ๋ก ํน์ ์์๋ฅผ ๋ณ๊ฒฝํ ๋๋ O(log n)
๋งํผ์ ์ฐ์ฐ๋ง ์ํํ๋ฉด ๋๋ค.
๊ตฌํ
void updateTree(int[] arr, int treeStart, int treeEnd, int node, int index, int diff) {
// ํ์ฌ ๋
ธ๋์ ํํ๋ ๊ตฌ๊ฐ์ด ํ์์ ์ํ๋ ๊ตฌ๊ฐ์ ์์ ํ ๋ฐฐ์ ํ๋ค๋ฉด pass
if (treeStart > index || treeEnd < index) return;
// ๊ฐ์ ๋ณ๊ฒฝํ ๋ฐฐ์ด ์์์ ํด๋น ์์ ๋ณํ๊ฐ ์ํฅ์ ๋ฏธ์น๋ ๋ชจ๋ ๋ถ๋ชจ ๋
ธ๋์ ๊ฐ์ ๋ณ๊ฒฝ(์ต์๊ฐ ๋ณ๊ฒฝ)
sTree[node] += diff;
// ์ต์ข
๋ฐฐ์ด ์์๊น์ง ๊ฐ์ ๋ณ๊ฒฝํ๋ค๋ฉด ์ฌ๊ท ์ข
๋ฃ
if (start == end) return;
// ๊ฐ์ ๋ณ๊ฒฝ์ ์ํ๋ ์์๊ฐ ํฌํจ๋ ๋ชจ๋ ๊ตฌ๊ฐ์ ์ต์๊ฐ์ ๋ฐ๊ฟ์ฃผ๊ธฐ ์ํด ์ฌ๊ท์ ์ผ๋ก ํ์
int mid = getMid(treeStart, treeEnd); // ํ์ฌ ํธ๋ฆฌ์ ๊ตฌ๊ฐ์ ๋๋
// ๊ฐ์ ๋ณ๊ฒฝ์ ์ํ๋ ์์๊ฐ ํฌํจ๋ ๊ตฌ๊ฐ์ ์ต์๊ฐ์ ๋ชจ๋ ๋ฐ๊ฟ์ค
updateTree(arr, treeStart, mid, 2*node, index, diff);
updateTree(arr, mid+1, treeEnd, 2*node+1, index, diff);
}