๐Ÿ“ Coding Test Study/Algorithm

[Algorithm] ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ(Segment Tree)

ibelieveinme 2024. 6. 8. 13:59
728x90

๊ตฌ๊ฐ„ํ•ฉ, ๊ตฌ๊ฐ„์— ๋”ฐ๋ฅธ ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ์—์„œ ๋งŽ์ด ์“ฐ์ด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ธ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

 

* ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ ๋ฐ ํ•„์š”์„ฑ

S[0] = A[0];
for (int i=1; i<n; i++) {
    S[i] = S[i-1] + A[i];
}

 

๊ตฌ๊ฐ„ํ•ฉ์„ ๋‹จ์ˆœ for ๋ฌธ์„ ์ด์šฉํ•ด์„œ ๊ตฌํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

0~n ๊นŒ์ง€์˜ ํ•ฉ์„ ๊ตฌํ•  ๋•Œ O(n) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

0~n ๋ฟ ์•„๋‹ˆ๋ผ 2~5, 100~200 ๋“ฑ m ๊ฐœ์˜ ๊ตฌ๊ฐ„ํ•ฉ์„ ๊ตฌํ•œ๋‹ค๋ฉด O(nm) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

์—ฌ๊ธฐ์„œ ๋งŒ์•ฝ A[x] ์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ.

A[x] ๊ฐ’์ด ํฌํ•จ๋œ ๋ชจ๋“  S ๋ฐฐ์—ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์„œ ๋‹ค์‹œ ๊ตฌ๊ฐ„ํ•ฉ์„ ๊ตฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

0๋ฒˆ ๊ฐ’์ด๋ผ๊ณ  ํ•˜๋ฉด ๋˜ O(nm) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

ํฐ ์ˆ˜์˜ n, m ์ด ์ฃผ์–ด์ง€๋ฉด ์‹œ๊ฐ„์ดˆ๊ณผ๋กœ ํ’€ ์ˆ˜ ์—†๋‹ค. ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„์•ผ ํ•œ๋‹ค.


* ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋ž€ ?

: ๊ตฌ๊ฐ„์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํŠธ๋ฆฌ.

 

- ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ๋ฆฌํ”„๋…ธ๋“œ: ๋ฐฐ์—ด์˜ ๊ทธ ์ˆ˜ ์ž์ฒด

- ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ๋‹ค๋ฅธ ๋…ธ๋“œ: ์™ผ์ชฝ ์ž์‹๊ณผ ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ํ•ฉ

- ํ•œ ๋…ธ๋“œ์˜ ๋ฒˆํ˜ธ๊ฐ€ x์ผ ๋•Œ ์™ผ์ชฝ ์ž์‹์˜ ๋ฒˆํ˜ธ๋Š” 2*x, ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๋ฒˆํ˜ธ๋Š” 2*x + 1 ์ด ๋œ๋‹ค.

 

n = 10 ์ธ ๋ฐฐ์—ด์„ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋กœ ํ‘œํ˜„ํ•ด๋ณด์ž.

์ถœ์ฒ˜: https://www.acmicpc.net/blog/view/9

 

๋ฆฌํ”„ ๋…ธ๋“œ์— ๊ฐ ๋ฐฐ์—ด์˜ index ๊ฐ€ ๋“ค์–ด ์žˆ๊ณ , ์ ์  ๋ฃจํŠธ ๋…ธ๋“œ๋กœ ๊ฐ€๋ฉฐ 0~1์˜ ํ•ฉ, 0~1๊ณผ 2์˜ ํ•ฉ, 3๊ณผ 4์˜ ํ•ฉ, 0~2์™€ 3~4์˜ ํ•ฉ, 0~4์™€ 5~9์˜ ํ•ฉ์ด ๋‹ด๊ธด๋‹ค. ์‹œ๊ฐ„๋ณต์žก๋„ O(logN).

 

์™ผ์ชฝ, ์˜ค๋ฅธ์ชฝ ํŠธ๋ฆฌ์˜ ๋‚˜๋ˆ” ๊ธฐ์ค€์€ ๋ฐฐ์—ด ํฌ๊ธฐ์˜ ๋ฐ˜์ด๋‹ค.(์œ„์— ์ ์€ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ํŠน์ง•์œผ๋กœ ํ•œ ๋…ธ๋“œ์˜ ๋ฒˆํ˜ธ๊ฐ€ x์ผ ๋•Œ ์™ผ์ชฝ ์ž์‹์˜ ๋ฒˆํ˜ธ๋Š” 2*x, ์˜ค๋ฅธ์ชฝ ์ž์‹์˜ ๋ฒˆํ˜ธ๋Š” 2*x + 1 ์ด๊ธฐ ๋•Œ๋ฌธ.)

 

์ฆ‰, 0~9์˜ ๊ตฌ๊ฐ„ํ•ฉ์„ ๊ตฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ฃจํŠธ๋…ธ๋“œ๋งŒ ์ ‘๊ทผํ•˜๋ฉด ๋œ๋‹ค.

5~8์˜ ๊ตฌ๊ฐ„ ํ•ฉ์„ ๊ตฌํ•ด์•ผ ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด 2๊ฐœ์˜ ๋…ธ๋“œ๋งŒ ์ ‘๊ทผํ•˜๋ฉด ๋œ๋‹ค.

์ถœ์ฒ˜: https://www.acmicpc.net/blog/view/9

 

3~9์˜ ๊ตฌ๊ฐ„ํ•ฉ์„ ๊ตฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์•„๋ž˜์™€ ๊ฐ™์ด 2๊ฐœ์˜ ๋…ธ๋“œ๋งŒ ์ ‘๊ทผํ•˜๋ฉด ๋œ๋‹ค.

์ถœ์ฒ˜: https://www.acmicpc.net/blog/view/9

 

๋ฐฐ์—ด์˜ ์–ด๋–ค ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ๋•Œ๋„ ํ•ด๋‹น ๊ฐ’์„ ํฌํ•จํ•˜๋Š” ๊ฐ’๊ณผ ๊ตฌ๊ฐ„ ๋…ธ๋“œ๋งŒ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์ถœ์ฒ˜: https://www.acmicpc.net/blog/view/9

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๊ฐ€ ์•„๋‹ˆ์—ˆ๋‹ค๋ฉด ๋ชจ๋“  ๊ตฌ๊ฐ„ํ•ฉ์— ์ ‘๊ทผํ•˜์—ฌ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ ํ–ˆ์„ ๊ฒƒ์ด๋‹ค. ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด 4๊ฐœ์˜ ๊ตฌ๊ฐ„ํ•ฉ์—๋งŒ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ๋œ๋‹ค. ์‹œ๊ฐ„๋ณต์žก๋„ O(logN).

 

 

* ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๋งŒ๋“œ๋Š” ๋ฒ•(C++)

1) ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์ƒ์„ฑ

// a: ๋ฐฐ์—ด a
// tree: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ
// node: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๋…ธ๋“œ ๋ฒˆํ˜ธ
// node๊ฐ€ ๋‹ด๋‹นํ•˜๋Š” ํ•ฉ์˜ ๋ฒ”์œ„๊ฐ€ start ~ end
long long init(vector<long long> &a, vector<long long> &tree, int node, int start, int end){
    if(start == end){
    	return tree[node] = a[start];
    } else{
    	return tree[node] = init(a, tree, node*2, start, (start+end)/2) + init(a, tree, node*2+1, (start+end)/2+1, end);
    }
}

start == end ์ธ ๊ฒฝ์šฐ๋Š” ๋ฆฌํ”„๋…ธ๋“œ๋ฅผ ๋œปํ•˜๋ฏ€๋กœ ๋ฆฌํ”„๋…ธ๋“œ๋Š” ๋ฐฐ์—ด ์ž์ฒด์˜ ๊ฐ’์ด ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ tree[node] ์— a[start] ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค.

๋ฆฌํ”„๋…ธ๋“œ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—” tree[node] ์— ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’๊ณผ ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’์„ ๋”ํ•ด์„œ ๋„ฃ์–ด์ค€๋‹ค.

 

2) ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๊ตฌ๊ฐ„ํ•ฉ ๊ตฌํ•˜๊ธฐ

// node ๊ฐ€ ๋‹ด๋‹นํ•˜๋Š” ๊ตฌ๊ฐ„: start ~ end
// ๊ตฌํ•ด์•ผํ•˜๋Š” ํ•ฉ์˜ ๋ฒ”์œ„: left ~ right
long long sum(vector<long long> &tree, int node, int start, int end, int left, int right) {
     if(left > end || right < start) {
     	return 0;
     }
     if(left <= start && end <= right) {
     	return tree[node];
     }
     return sum(tree, node*2, start, (start+end)/2, left, right) + sum(tree, node*2+1, start+end)/2+1, end, left, right);
}

 

๊ตฌํ•ด์•ผํ•˜๋Š” ๊ตฌ๊ฐ„ํ•ฉ [left, right] ์˜ ๋ฒ”์œ„๊ฐ€ [start, end] ์— ํ•˜๋‚˜๋ผ๋„ ์—†๋‹ค๋ฉด 0์„ return ํ•œ๋‹ค.

๊ตฌํ•ด์•ผํ•˜๋Š” ๊ตฌ๊ฐ„ํ•ฉ [left, right] ์˜ ๋ฒ”์œ„๊ฐ€ [start, end] ์•ˆ์— ์™„์ „ํžˆ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น node ๊ฐ’์„ ๋ฐ”๋กœ return ํ•œ๋‹ค.

๊ทธ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์™ผ์ชฝ, ์˜ค๋ฅธ์ชฝ ๋…ธ๋“œ ํƒ์ƒ‰์„ ํ†ตํ•ด ๊ฐ’์„ ๊ตฌํ•œ๋‹ค.

 

3) ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๋…ธ๋“œ ๊ฐ’ ๋ณ€๊ฒฝํ•˜๊ธฐ

// tree: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ
// node: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ํ˜„์žฌ ๋…ธ๋“œ ๋ฒˆํ˜ธ
// node ๊ฐ€ ๋‹ด๋‹นํ•˜๋Š” ํ•ฉ์˜ ๋ฒ”์œ„ start ~ end
// index: ์ˆ˜์ •ํ•ด์•ผํ•  ๋…ธ๋“œ์˜ index
// diff: ๊ธฐ์กด ๊ฐ’๊ณผ ๋ณ€๊ฒฝํ•  ๊ฐ’์˜ ์ฐจ์ด
void update(vector<long long> &tree, int node, int start, int end, int index, long long diff) {
    if (index < start || index > end) return;
    tree[node] = tree[node] + diff;
    if (start != end) {
        update(tree,node*2, start, (start+end)/2, index, diff);
        update(tree,node*2+1, (start+end)/2+1, end, index, diff);
    }
}

index ๊ฐ€ start ์™€ end ์‚ฌ์ด์˜ ๊ฐ’์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ฐ”๋กœ return ํ•œ๋‹ค.

index ๊ฐ€ start ์™€ end ์‚ฌ์ด์˜ ๊ฐ’์ด๋ผ๋ฉด diff ๋งŒํผ์„ ๋”ํ•ด์„œ ๊ฐ’์„ ๊ฐฑ์‹ ํ•œ๋‹ค.

leef ๋…ธ๋“œ๊ฐ€ ์•„๋‹ˆ๋ฉด ์™ผ์ชฝ, ์˜ค๋ฅธ์ชฝ ์ž์‹ ํŠธ๋ฆฌ์˜ ๋…ธ๋“œ๋ฅผ update ํ•˜๋Ÿฌ ๊ฐ„๋‹ค.


* ์ถœ์ฒ˜ : https://www.acmicpc.net/blog/view/9


* ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋กœ ํ’€ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ

2042๋ฒˆ ๊ตฌ๊ฐ„ํ•ฉ(https://www.acmicpc.net/problem/2042)

#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;

long long init(vector<long long> &a, vector<long long> &tree, int node, int start, int end) {
    if (start == end) {
        return tree[node] = a[start];
    } else {
        return tree[node] = init(a, tree, node*2, start, (start+end)/2) + init(a, tree, node*2+1, (start+end)/2+1, end);
    }
}
void update(vector<long long> &tree, int node, int start, int end, int index, long long diff) {
    if (index < start || index > end) return;
    tree[node] = tree[node] + diff;
    if (start != end) {
        update(tree,node*2, start, (start+end)/2, index, diff);
        update(tree,node*2+1, (start+end)/2+1, end, index, diff);
    }
}
long long sum(vector<long long> &tree, int node, int start, int end, int left, int right) {
    if (left > end || right < start) {
        return 0;
    }
    if (left <= start && end <= right) {
        return tree[node];
    }
    return sum(tree, node*2, start, (start+end)/2, left, right) + sum(tree, node*2+1, (start+end)/2+1, end, left, right);
}
int main() {
    int n, m, k;
    scanf("%d %d %d",&n,&m,&k);
    vector<long long> a(n);
    int h = (int)ceil(log2(n));
    int tree_size = (1 << (h+1));
    vector<long long> tree(tree_size);
    m += k;
    for (int i=0; i<n; i++) {
        scanf("%lld",&a[i]);
    }
    init(a, tree, 1, 0, n-1);
    while (m--) {
        int t1,t2,t3;
        scanf("%d",&t1);
        if (t1 == 1) {
            int t2;
            long long t3;
            scanf("%d %lld",&t2,&t3);
            t2-=1;
            long long diff = t3-a[t2];
            a[t2] = t3;
            update(tree, 1, 0, n-1, t2, diff);
        } else if (t1 == 2) {
            int t2,t3;
            scanf("%d %d",&t2,&t3);
            printf("%lld\n",sum(tree, 1, 0, n-1, t2-1, t3-1));
        }
    }
    return 0;
}
728x90