알고리즘

세그먼트 트리 합구하기

잔잔한 물결처럼 2025. 2. 14. 03:06

# 문제

2268번 : 수들의 합 7

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

 

 

세그먼트 트리를 이용해야 제한시간에 맞게 풀수 있는 문제이다.

 

내용자체는 복잡하지 않아서 세그먼트 트리를 알면 충분히 풀수 있는 문제이지만 자바에서는 index 가 0에서 부터 시작되는데 반해 문제에서는 index 가 1부터 시작하기 때문에 혼란이 올수 있다.

또 세그먼트 트리에 저장되는 값이 int 가 넘을 수 있기 때문에 반드시 long 자료형으로 배열을 선언해 주어야 올바른 답을 구할 수 있다.

그리고 입력되는 인자가 반드시 처음값보다 나중값이 크다는 보장이 없어서 이 부분도 처리해 주어야 한다.

 

우선 만약에 문제에서 인덱스가 1번부터 시작하는 경우 배열의 크기를 세그먼트 트리의 형태에 맞게 선언해주고 나서
시작점을 1빼주면 문제에서 입력값이 모두 -1빼지는 효과가 나서 자바와 문제사이의 index 시작점 문제를 해결 할 수 있다.

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

public class Main {
	static long[] tree;
	static int start;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		start = 1;
		while (start < N) start *= 2;
		tree = new long[start * 2];
		start--;
		Arrays.fill(tree, 0);
		int M = Integer.parseInt(st.nextToken());
		for (int i = 0; i < M; i++) {
			st = new StringTokenizer(br.readLine());
			int query = Integer.parseInt(st.nextToken());
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			if (query == 0) sum(a,b);
			else modify(a, b);
		}
	}
	static void sum(int a, int b) {
		int s = Math.min(a, b) + start;
		int e = Math.max(a, b) + start;
		long result = 0;
		while (s <= e) {
			if (s % 2 == 1) result += tree[s++];
			if (e % 2 == 0) result += tree[e--];
			s /= 2;
			e /= 2;
		}
		System.out.println(result);
	}
	static void modify(int a, int b) {
		int idx = a + start;
		tree[idx] = b;
		while (idx > 1) {
			idx /= 2;
			tree[idx] = tree[idx * 2] + tree[idx * 2 + 1]; 
		}
	}
}

 

함수를 적당히 분리해서 코딩을 하니 좀더 깔끔한 느낌이 든다.