[백준] Baekjoon Online Judge
문제
어떤 N개의 수가 주어져 있다. 그런데 중간에 수의 변경이 빈번히 일어나고 그 중간에 어떤 부분의 곱을 구하려 한다. 만약에 1, 2, 3, 4, 5 라는 수가 있고, 3번째 수를 6으로 바꾸고 2번째부터 5번째까지 곱을 구하라고 한다면 240을 출력하면 되는 것이다. 그리고 그 상태에서 다섯 번째 수를 2로 바꾸고 3번째부터 5번째까지 곱을 구하라고 한다면 48이 될 것이다.
입력
첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 곱을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다. 그리고 N+2번째 줄부터 N+M+K+1 번째 줄까지 세 개의 정수 a,b,c가 주어지는데, a가 1인 경우 b번째 수를 c로 바꾸고 a가 2인 경우에는 b부터 c까지의 곱을 구하여 출력하면 된다.
입력으로 주어지는 모든 수는 0보다 크거나 같고, 1,000,000보다 작거나 같은 정수이다.
출력
첫째 줄부터 K줄에 걸쳐 구한 구간의 곱을 1,000,000,007로 나눈 나머지를 출력한다.
풀이
#include <iostream>
using namespace std;
#define MAX 1000001
#define MOD 1000000007
int N, M, K;
long long arr[MAX];
long long tree[MAX * 4];
long long init(int start, int end, int node);
void update(int start, int end, int node, int idx, long long data);
long long find(int start, int end, int node, int left, int right);
// 세그먼트 트리 초기화
long long init(int start, int end, int node) {
if (start == end) return tree[node] = arr[start];
int mid = (start + end) / 2;
return tree[node] = (init(start, mid, node * 2) % MOD * init(mid + 1, end, node * 2 + 1) % MOD) % MOD;
}
// 세그먼트 트리 업데이트
void update(int start, int end, int node, int idx, long long data) {
if (idx < start || idx > end) return;
if (start == end) {
tree[node] = data;
return;
}
int mid = (start + end) / 2;
update(start, mid, node * 2, idx, data);
update(mid + 1, end, node * 2 + 1, idx, data);
tree[node] = (tree[node * 2] * tree[node * 2 + 1]) % MOD;
}
// 구간 곱 구하기
long long find(int start, int end, int node, int left, int right) {
// 탐색 범위가 원하는 구간 밖이라면
if (left > end || right < start) return 1;
// 탐색 범위가 원하는 구간 안이라면
if (left <= start && end <= right) return tree[node];
int mid = (start + end) / 2;
return (find(start, mid, node * 2, left, right) * find(mid + 1, end, node * 2 + 1, left, right)) % MOD;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N >> M >> K;
for (int i = 1; i <= N; i++) cin >> arr[i];
init(1, N, 1);
for (int i = 0; i < M + K; i++) {
long long a, b, c;
cin >> a >> b >> c;
if (a == 1)
update(1, N, 1, b, c);
else
cout << find(1, N, 1, b, c) % MOD << '\n';
}
return 0;
}
// 세그먼트 트리 초기화
long long init(int start, int end, int node) {
if (start == end) return tree[node] = arr[start];
int mid = (start + end) / 2;
return tree[node] = (init(start, mid, node * 2) % MOD * init(mid + 1, end, node * 2 + 1) % MOD) % MOD;
}
입력 받은 배열로 세그먼트 트리를 만드는 함수이다. 범위 초과를 방지하기 위해 1,000,000,007로 나눈 나머지를 tree에 저장하도록 했다.
// 세그먼트 트리 업데이트
void update(int start, int end, int node, int idx, long long data) {
if (idx < start || idx > end) return;
if (start == end) {
tree[node] = data;
return;
}
int mid = (start + end) / 2;
update(start, mid, node * 2, idx, data);
update(mid + 1, end, node * 2 + 1, idx, data);
tree[node] = (tree[node * 2] * tree[node * 2 + 1]) % MOD;
}
숫자 변경 시 세그먼트 트리를 업데이트하는 함수이다.
// 구간 곱 구하기
long long find(int start, int end, int node, int left, int right) {
// 탐색 범위가 원하는 구간 밖이라면
if (left > end || right < start) return 1;
// 탐색 범위가 원하는 구간 안이라면
if (left <= start && end <= right) return tree[node];
int mid = (start + end) / 2;
return (find(start, mid, node * 2, left, right) * find(mid + 1, end, node * 2 + 1, left, right)) % MOD;
}
구간 곱을 return하는 함수이다. 탐색 범위가 원하는 구간을 넘어간다면 값에 영향을 주지 않는 1을 return하고, 탐색 범위가 원하는 구간에 속한다면 tree의 값을 return한다.
'백준 > C++' 카테고리의 다른 글
[Baekjoon/C++] 11504번 - 돌려 돌려 돌림판! (0) | 2025.04.12 |
---|---|
[Baekjoon/C++] 5032번 - 탄산 음료 (0) | 2025.04.11 |
[Baekjoon/C++] 29615번 - 알파빌과 베타빌 (0) | 2025.04.09 |
[Baekjoon/C++] 3226번 - 전화 요금 (0) | 2025.04.08 |
[Baekjoon/C++] 20006번 - 랭킹전 대기열 (0) | 2025.04.07 |