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

[백준][JAVA] 11505번 구간 곱 구하기

by 박뀨뀨 2024. 2. 8.

 

 

11505번: 구간 곱 구하기

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

www.acmicpc.net

코드

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

public class Main {

	static final int MOD = 1000000007;
	static int N, M, K, H, treeSize; // 수의 개수, 변경발생횟수, 구간곱계산횟수, 세그먼트트리높이, 세그먼트트리노드개수
	static long A[], tree[]; // 수저장배열, 세그먼트트리
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		
		StringTokenizer st = new StringTokenizer(br.readLine());

		N = Integer.parseInt(st.nextToken()); // 수의 개수 (1 ~ 1000000)
		M = Integer.parseInt(st.nextToken()); // 변경이 일어나는 횟수 (1 ~ 10000)
		K = Integer.parseInt(st.nextToken()); // 구간의 곱을 구하는 횟수 (1 ~ 10000)
		
		H = (int) (Math.ceil(Math.log(N) / Math.log(2))); // 세그먼트트리 높이
		treeSize = 1 << (H + 1); // 세그먼트트리에 필요한 노드갯수
		tree = new long[treeSize];
		
		A = new long[N];
		
		for (int i = 0; i < N; i++) {
			A[i] = Long.parseLong(br.readLine());
		}
		
		build(1, 0, N - 1);
		
		for (int i = 0; i < M + K; i++) {
			st = new StringTokenizer(br.readLine());
			
			int a = Integer.parseInt(st.nextToken()); // 1인 경우 b번째 수 c로 전환, 2인 경우 b부터 c까지 곱 계산
			int b = Integer.parseInt(st.nextToken());
			int c = Integer.parseInt(st.nextToken());
			
			if (a == 1) {
				update(1, 0, N - 1, b - 1, c);
			} else if (a == 2) {
				sb.append(query(1, 0, N - 1, b - 1, c - 1)).append("\n");
			}
		}
		
		System.out.print(sb);
	}

	// 세그먼트 트리 변경 작업 메서드
	// index번째 배열 A를 val로 바꿈과 동시에 세그먼트트리에서 index가 포함된 구간을 담당하는 노드값도 갱신
	static void update(int node, int start, int end, int index, int val) {
		
		if (start == end) { // 리프노드에 도달한 경우
			tree[node] = val; // 리프노드 값을 val로 변경
			return;
		}
		
		int mid = (start + end) / 2;
		
		if (start <= index && index <= mid) { // index가 왼쪽서브트리내에 포함된 경우
			update(node * 2, start, mid, index, val);
		} else { // index가 오른쪽서브트리내에 포함된 경우
			update(node * 2 + 1, mid + 1, end, index, val);
		}
		
		tree[node] = (tree[node * 2] * tree[node * 2 + 1]) % MOD; // 해당 node의 세그먼트트리값을 왼쪽자식과 오른쪽자식을 곱한후 1000000007로 나눈 나머지값으로 변경
	}

	// 세그먼트 트리 구간 탐색 메서드
	// 현재구간이(start,end) 탐색구간(left, right)를 벗어난 경우 1 리턴
	// 현재구간이(start,end) 탐색구간(left, right)내에 속한 경우 해당 node에 속하는 세그먼트트리값 리턴
	// 그외의 경우 왼쪽 자식과 오른쪽 자식 결과값을 곱한뒤 1000000007로 나눈 나머지값 리턴
	static long query(int node, int start, int end, int left, int right) {
		
		if (end < left || right < start) {
			return 1;
		}
		
		if (left <= start && end <= right) {
			return tree[node];
		}
		
		int mid = (start + end) / 2;
		long leftChild = query(node * 2, start, mid, left, right);
		long rightChild = query(node * 2 + 1, mid + 1, end, left, right);
		
		return (leftChild * rightChild) % MOD;
	}

	// 세그먼트 트리 생성 작업 메서드
	static void build(int node, int start, int end) {
		if (start == end) { // 리프노드 도달한 경우
			tree[node] = A[start]; // 리프노드에 해당 노드번호에 해당하는 값(A[start]) 저장
			return;
		}
		
		int mid = (start + end) / 2;
		build(node * 2, start, mid);
		build(node * 2 + 1, mid + 1, end);
		tree[node] = (tree[node * 2] * tree[node * 2 + 1]) % MOD; // 왼쪽 자식과 오른쪽 자식을 곱하고 나머지 1000000007로 나눈 나머지값 저장
	}

}
728x90

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

[백준][JAVA] 2357번 최솟값과 최댓값  (1) 2023.12.16