문제
https://www.acmicpc.net/problem/2357
풀이(20분)
import java.io.*;
import java.util.*;
public class Main {
static int[] maxSegmentTree, minSegmentTree;
static int squareNum;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken()); // 수의 개수
int m = Integer.parseInt(st.nextToken()); // 질의 개수
int square = 0; // 2^k >= n 을 만족하기 위한 수
while(Math.pow(2, square) < n){
square++;
}
squareNum = (int)Math.pow(2, square);
maxSegmentTree = new int[(int)Math.pow(2,square+1)]; // 2^k * 2로 배열 초기화
minSegmentTree = new int[(int)Math.pow(2,square+1)]; // 2^k * 2로 배열 초기화
Arrays.fill(minSegmentTree, Integer.MAX_VALUE);
for(int i = squareNum; i < squareNum + n; i++){
int input = Integer.parseInt(br.readLine()); // 2^k 부터 값 저장.
maxSegmentTree[i] = input; // 2^k 부터 값 저장.
minSegmentTree[i] = input; // 2^k 부터 값 저장.
}
for(int i = squareNum * 2 - 1; i >= 2; i--){
maxSegmentTree[i/2] = Math.max(maxSegmentTree[i/2],maxSegmentTree[i]);
minSegmentTree[i/2] = Math.min(minSegmentTree[i/2],minSegmentTree[i]);
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < m; i++){
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int temp = a;
if(a > b){
a = b;
b = temp;
}
int[] answer = query(a, b);
sb.append(answer[0]).append(" ").append(answer[1]).append("\n");
}
System.out.println(sb);
}
static int[] query(int start, int end) {
start += squareNum - 1; // 리프 노드 시작 인덱스로 이동
end += squareNum - 1;
int max = 0;
int min = Integer.MAX_VALUE;
while (start <= end) {
// start가 오른쪽 자식이면 해당 노드 포함 후, 다음 노드로 이동
if (start % 2 == 1) {
max = Math.max(max, maxSegmentTree[start]);
min = Math.min(min, minSegmentTree[start]);
start++;
}
// end가 왼쪽 자식이면 해당 노드 포함 후, 이전 노드로 이동
if (end % 2 == 0) {
max = Math.max(max, maxSegmentTree[end]);
min = Math.min(min, minSegmentTree[end]);
end--;
}
// 부모 노드로 이동
start /= 2;
end /= 2;
}
int[] answer = new int[2];
answer[0] = min;
answer[1] = max;
return answer;
}
}
문제 풀이 전략
세그먼트 트리의 3대장중 하나인 최대와 최소이다. 세그먼트 트리를 모른다면 아래 링크를 참고하자.
[도구정리] 세그먼트 트리(Segment Tree) 알고리즘
진행하는 과정에서 생길 수 있는 부분에 대해서는 Q.라고 적어두고 하단부에 모두 설명할 테니 참고하자. 개념주어진 데이터의 구간 합과 데이터 업데이트를 빠르게 수행하기 위해 고안해낸 자
to-travel-coding.tistory.com
세그먼트 트리에서 업데이트를 하는 것은 사용되지 않았지만, 여러 질의에 있어 최대와 최소를 n개 탐색하지 않고 효율적으로 구할 수 있게 된다. minSegmentTree의 경우 초기값을 Integer.MAX_VLAUE로 하여 최솟값을 추적할 수 있게 한다.
만약, update가 발생하는 상황이 있다면 업데이트가 이루어지지 않는 시점까지만 반복을 하는 식의 최적화를 할 수도 있다.
'문제 풀이 > 백준' 카테고리의 다른 글
[백준] 1132번. 합(JAVA) (1) | 2025.04.16 |
---|---|
[백준] 14428번. 수열과 쿼리 16(JAVA) (0) | 2025.04.14 |
[백준] 11505번. 구간 곱 구하기(JAVA) (0) | 2025.04.13 |
[백준] 2042번. 구간 합 구하기(JAVA) (0) | 2025.04.13 |
[백준] 1019번. 책 페이지(JAVA) (0) | 2025.04.11 |