알고리즘 문제/[백준]

[백준] 10868 최솟값

latter2005 2020. 12. 15. 03:50

문제 주소 : www.acmicpc.net/problem/10868

 

10868번: 최솟값

N(1 ≤ N ≤ 100,000)개의 정수들이 있을 때, a번째 정수부터 b번째 정수까지 중에서 제일 작은 정수를 찾는 것은 어려운 일이 아니다. 하지만 이와 같은 a, b의 쌍이 M(1 ≤ M ≤ 100,000)개 주어졌을 때는

www.acmicpc.net

문제 확인

 

문제에서 쿼리의 개수가 최대 10만 개 이므로 단순히 계산으로 풀면 시간 초과가 나게 됩니다.

따라서 쿼리에 따른 처리법인 mo's 알고리즘 혹은 세그먼트 트리를 통해 풀 수 있습니다.

처음엔 mo's 알고리즘으로 쿼리를 전처리 후 정렬된 query 순으로 풀어나가는 방법으로 시도하였습니다. 기록해둔 쿼리의 범위가 현재 쿼리의 범위보다 넓은 경우엔 최솟값 갱신을 쉽게 할 수 있지만 반대의 경우엔 어느 위치에 최솟값이 위치하는지 알 수 없으므로 새로 찾아야 하기 때문에 연산 횟수가 많아져 세그먼트 트리를 활용하게 되었습니다.

세그먼트 트리 : latter2005.tistory.com/28

 

[자료구조] 세그먼트 트리

자료구조 설명 : www.acmicpc.net/blog/view/9 세그먼트 트리 (Segment Tree) 문제 배열 A가 있고, 여기서 다음과 같은 두 연산을 수행해야하는 문제를 생각해봅시다. 구간 l, r (l ≤ r)이 주어졌을 때, A[l] + A..

latter2005.tistory.com

 

풀이

 

값 갱신이 없으므로 값을 입력받는 즉시 세그먼트 트리 데이터 부분에 저장합니다.

사용한 iterative 세그먼트 트리에서 범위에서 벗어나는 구간을 의미하는 홀수를 이용하여 구간 최솟값을 구해나갑니다.

 

코드

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <cstdio>
#include <algorithm>
#include <sys/stat.h>
#include <sys/mman.h>
 
class fio {
    size_t rsize;
    unsigned char* rbuf;
    static const int wsize = 0xffff;
    unsigned char wbuf[wsize];
    int ridx, widx;
 
public:
    fio() : ridx(0), widx(0) {
        struct stat rstat;
        fstat(0&rstat);
        rsize = rstat.st_size;
        rbuf = (unsigned char*)mmap(0, rsize, PROT_READ, MAP_FILE | MAP_PRIVATE, 00);
    }
 
    inline bool isBlank() {
        return
            !(rbuf[ridx] != '\n' && rbuf[ridx] != '\t' && rbuf[ridx] != '\r' &&
            rbuf[ridx] != '\f' && rbuf[ridx] != '\v' && rbuf[ridx] != ' ');
    }
    inline void consumeBlank() { while (isBlank()) ridx++; }
 
    int readInt() {
        int res = 0, flag = 0;
        consumeBlank();
        if (rbuf[ridx] == '-') {
            flag = 1;
            ridx++;
        }
        while (!isBlank() && ridx < rsize)
            res = 10 * res + rbuf[ridx++- '0';
        return flag ? -res : res;
    }
 
    inline void flush() {
        fwrite(wbuf, 1, widx, stdout);
        widx = 0;
    }
 
    inline int intSize(int x) {
        int cnt = 1;
        x = (x > 0) ? x : -x;
        while (x /= 10) cnt++;
        return cnt;
    }
 
    inline void check(int n) { if (widx + n >= wsize) flush(); }
    inline void writeChar(char z) { check(1); wbuf[widx++= z; }
 
    void writeInt(int x) {
        int sz = intSize(x);
        check(sz);
        if (x < 0) {
            writeChar('-');
            x = -x;
        }
        for (int i = 1; i <= sz; ++i) {
            wbuf[widx + sz - i] = x % 10 + '0';
            x /= 10;
        }
        widx += sz;
    }
};
using namespace std;
 
int main() {
    fio fo;
    int tree[200002];
    int n = fo.readInt(), m = fo.readInt();
    for (int i = 0; i < n; i++)
        tree[n + i] = fo.readInt();//입력
    for (int i = n - 1; i > 0; i--)
        tree[i] = min(tree[i << 1], tree[i << 1 | 1]);//트리 생성
    while (m--) {
        int s = fo.readInt(), e = fo.readInt(), mn = 0x7fffffff;
        for (s += n - 1, e += n; s < e; s >>= 1, e >>= 1) {
            if (s & 1) mn = min(tree[s++], mn);//왼쪽 벗어나는 범위
            if (e & 1) mn = min(tree[--e], mn);//오른쪽 벗어나는 범위
        }
        fo.writeInt(mn);
        fo.writeChar('\n');
    }
    fo.flush();
}
 
cs
반응형

'알고리즘 문제 > [백준]' 카테고리의 다른 글

[백준] 15685 드래곤 커브  (0) 2020.12.17
[백준] 2357 최솟값과 최댓값  (0) 2020.12.17
[백준] 1744 수 묶기  (0) 2020.12.12
[백준] 19236 청소년 상어  (0) 2020.12.09
[백준] 16637 괄호 추가하기  (0) 2020.12.05