투로드
Coder ToLoad
투로드
전체 방문자
오늘
어제

블로그 메뉴

  • 홈
  • 알고리즘
  • CS
  • GITHUB
  • 태그
  • 분류 전체보기 (69)
    • Toy Project (0)
      • EternalSNS (0)
    • Algorithm (46)
      • BaekJoon (38)
      • Programmers (7)
      • Code Tree (1)
    • Computer Science (13)
      • JAVA (7)
      • DataBase (4)
    • Backend (7)
      • Spring (2)
      • JPA (2)
      • Django (3)
    • Mobile (2)
      • Android (2)
    • Unity (1)

인기 글

최근 글

hELLO · Designed By 정상우.
투로드

Coder ToLoad

Algorithm/BaekJoon

[JAVA] 백준 2042 : 구간 합 구하기

2023. 4. 13. 01:08

문제

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net

 

해결방법

안녕하세요 !

글은 쓰고 있지 않지만 꾸준히 알고리즘을 풀이하고는 있는데 최근에 세그먼트 트리를 하게 되면서 기본 구조를 알 수 있는 문제는 기록을 해두면 좋을 것 같아서 오랜만에 글을 작성해 봅니다.

 

세그먼트 트리는 누적합의 다음 형태라고 볼 수 있는데

누적합의 경우 구간의 합은 O(1)에 구해지지만 중간에 값이 업데이트가 될 경우 O(N)만큼 시간이 소모되기 때문에 업데이트 횟수가 많다면 사용하기 부적합합니다.

이를 대체하기 위해 세그먼트 트리를 사용하는데 세그먼트 트리는 업데이트와 구간합 모두 O(logN)에 가능하기 때문에 훨씬 효율적이라고 할 수 있습니다.

 

자세한 설명은 여기 블로그에 소개가 잘 되어있으니 참고해 주세요.

저도 오랜만에 세그먼트 트리를 보다보니 코드가 잘 생각이 안나서 참고하면서 풀었습니다.

 

[Java] 세그먼트 트리(Segment Tree)

세그먼트 트리는 리프 노드를 제외한 다른 모든 노드는 항상 2개의 자식을 가집니다.

velog.io


이 문제는 위에서 설명한 세그먼트 트리를 활용하는 기초적인 문제라고 볼 수 있는데 특이사항으론 주어지는 수의 범위가 2의 63 제곱까지여서 long을 사용해주셔야 합니다.

자세한 내용은 코드를 보면서 확인해 주세요 !

 

코드

import java.util.*;
import java.io.*;

public class bj_2042 {
    static final int CHANGE = 1;
    static final int SUM = 2;

    static int N;
    static long[] number;
    static long[] segmentTree;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        int K = Integer.parseInt(st.nextToken());

        number = new long[N + 1];
        for (int i = 1; i <= N; i++) {
            number[i] = Long.parseLong(br.readLine());
        }

        segmentTree = new long[(N + 1) * 4];
        makeTree(1, N, 1);

        for (int i = 0; i < M + K; i++) {
            st = new StringTokenizer(br.readLine());
            int mode = Integer.parseInt(st.nextToken());

            if (mode == CHANGE) {
                int id = Integer.parseInt(st.nextToken());
                long newNumber = Long.parseLong(st.nextToken());

                updateTree(1, N, 1, id, newNumber - number[id]);
                number[id] = newNumber;
            } else if (mode == SUM) {
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());

                if (a < b)
                    System.out.println(getSum(1, N, 1, a, b));
                else
                    System.out.println(getSum(1, N, 1, b, a));
            }
        }
    }

    static long makeTree(int start, int end, int index) {
    	// 모든 구간 완료시 종료
        if (start == end) return segmentTree[index] = number[start];

        int mid = (start + end) / 2;
        return segmentTree[index] = makeTree(start, mid, index * 2) + makeTree(mid + 1, end, index * 2 + 1);
    }

    static void updateTree(int start, int end, int index, int id, long value) {
    	// 범위에서 벗어나면 종료
        if (id < start || id > end) return;

        // 범위에 포함되면 값을 변경
        segmentTree[index] += value;
        if (start == end) return; // 트리 제일 아래까지 탐색완료시 종료

        int mid = (start + end) / 2;
        updateTree(start, mid, index * 2, id, value);
        updateTree(mid + 1, end, index * 2 + 1, id, value);
    }

    static long getSum(int start, int end, int index, int left, int right) {
        if (right < start || left > end) return 0; // 범위에서 벗어나면 종료
        if (left <= start && right >= end) return segmentTree[index]; // 범위를 포함하고 있으면 값을 리턴

        int mid = (start + end) / 2;
        return getSum(start, mid, index * 2, left, right) + getSum(mid + 1, end, index * 2 + 1, left, right);
    }
}
저작자표시 비영리 (새창열림)

'Algorithm > BaekJoon' 카테고리의 다른 글

[JAVA] 백준 12764 : 싸지방에 간 준하  (0) 2022.10.27
[JAVA] 백준 17141 : 연구소 2  (0) 2021.12.27
[JAVA] 백준 1766 : 문제집  (0) 2021.12.19
[JAVA] 백준 1162 : 도로포장  (0) 2021.12.16
[JAVA] 백준 1963 : 소수 경로  (0) 2021.11.30
    'Algorithm/BaekJoon' 카테고리의 다른 글
    • [JAVA] 백준 12764 : 싸지방에 간 준하
    • [JAVA] 백준 17141 : 연구소 2
    • [JAVA] 백준 1766 : 문제집
    • [JAVA] 백준 1162 : 도로포장
    투로드
    투로드
    훌륭한 프로그래머가 되어가는 과정을 담아보는 중입니다.

    티스토리툴바