본문 바로가기
알고리즘/세그먼트트리

[백준][JAVA] 2357번 최솟값과 최댓값

by 박뀨뀨 2023. 12. 16.
 

2357번: 최솟값과 최댓값

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

www.acmicpc.net

코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    static int N, M, H, treeSize, tree[], A[];

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken()); // 정수의 개수 (1 ~ 100000)
        M = Integer.parseInt(st.nextToken()); // 쌍의 개수 (1 ~ 100000)

        H = (int) (Math.ceil(Math.log(N) / Math.log(2))); // 세그먼트 트리의 높이
        treeSize = 1 << (H + 1); // 트리에 필요한 노드의 갯수
        tree = new int[treeSize]; // 세그먼트 트리 배열 초기화

        A = new int[N]; // 정수를 저장할 배열

        for (int i = 0; i < N; i++) {
            A[i] = Integer.parseInt(br.readLine());
        }

        build(1, 0, N - 1); // 세그먼트 트리 생성

        for (int i = 0; i < M; i++) { // M개의 쌍
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken()) - 1; // 첫번째부터 시작하므로 1빼서 A의 인덱스와 맞춰줬음
            int b = Integer.parseInt(st.nextToken()) - 1; // 위와 동일한 이유로 1빼줬음
            int min = query(1, 0, N - 1, a, b); // a,b구간 내에서 최솟값 찾음
            sb.append(min).append("\n"); // 출력 결과 저장
        }

        System.out.print(sb); // M개의 입력 결과에 대한 출력 한번에  출력
    }

    // 세그먼트 트리에서 구간 내 최솟값을 찾는 메서드
    // 1. 탐색구간이 구간 밖을 벗어난 경우 무한대(1234567890) 리턴
    // 2. 탐색구간이 구간 내에 속한 경우 해당 node번호에 위치한 세그먼트트리값 리턴
    // 3. 그외의 경우 왼쪽서브트리와 오른쪽서브트리의 결과 중 최솟값 리턴
    static int query(int node, int start, int end, int left, int right) {
        if (right < start || end < left) { // 1.
            return 1234567890;
        }

        if (left <= start && end <= right) { // 2.
            return tree[node];
        }

        int mid = (start + end) / 2;
        int leftChild = query(node * 2, start, mid, left, right);
        int rightChild = query(node * 2 + 1, mid + 1, end, left, right);

        return Math.min(leftChild, rightChild); // 3.
    }

    // 세그먼트 트리를 만드는 작업
    // 1. 구간 시작과 끝이 같은 경우(리프노드) 해당 노드번호에 해당하는 곳에 정수 저장
    // 2. 그외의 경우 왼쪽 자식과 오른쪽 자식 중 최솟값 저장
    static void build(int node, int start, int end) {
        if (start == end) { // 1.
            tree[node] = A[start];
            return;
        }

        int mid = (start + end) / 2;
        build(node * 2, start, mid);
        build(node * 2 + 1, mid + 1, end);
        tree[node] = Math.min(tree[node * 2], tree[node * 2 + 1]); // 2.
    }

}
728x90

'알고리즘 > 세그먼트트리' 카테고리의 다른 글

[백준][JAVA] 11505번 구간 곱 구하기  (0) 2024.02.08