Home BOJ 10868 최솟값
Post
Cancel

BOJ 10868 최솟값

최솟값 [골드 1]


문제 링크

https://www.acmicpc.net/problem/10868

풀이

세그먼트 트리를 활용하여 문제를 푼다. 매번 주어진 범위를 구해 문제를 풀면 O(NM)의 시간복잡도를 갖기 때문에 시간 초과가 난다. 세그먼트 트리의 경우 범위 조회에는 O(lgN), 위 문제의 경우 업데이트는 없지만 O(lgN)의 시간 복잡도를 갖는다. 때문에 1초라는 시간 제한을 넘기지 않고 통과할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;

int init(vector<int> &a, vector<int> &tree, int node, int start, int end) {
    if(start == end) {	// leaf node
        return tree[node] = a[start];
    }
    else {	// node * 2 : 왼쪽 자식, node * 2 + 1 : 오른쪽 자식
        int mid = (start + end) / 2;
        return tree[node] = min(init(a, tree, node * 2, start, mid), init(a, tree, node * 2 + 1, mid + 1, end));
    }
}

// tree[node]는 start ~ end까지의 min 값을 갖고 있다.
int get(vector<int> &tree, int node, int start, int end, int left, int right) {
    if(left > end || right < start) {	// tree[node]의 범위를 벗어남
        return 1e9;
    }
    if(left <= start && end <= right) {	// 구하고자 하는 범위가 tree[node]를 완전히 포함하는 경우
        return tree[node];
    }
	
    // tree[node]가 left ~ right 일부를 포함하는 경우. 재귀를 통해 구한다.
    int mid = (start + end) / 2;
    return min(get(tree, node * 2, start , mid, left, right), get(tree, node*2+1, mid+1, end, left, right));
}

int main(void)
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int N, M, a, b;

    cin >> N >> M;
    vector<int> A(N);

    int h = (int)(ceil(log2(N)));
    int tree_size = 1 << (h + 1);
    vector<int> tree(tree_size);
    for (int i = 0; i < N; i++) {
        cin >> A[i];
    }

    init(A, tree, 1, 0, N - 1);

    for (int i = 0; i < M; i++) {
        cin >> a >> b;
        cout << get(tree, 1, 0, N - 1, a - 1, b - 1) << "\n";
    }

    return 0;
}
This post is licensed under CC BY 4.0 by the author.