"구간 합" 유형 + 값 수정 쿼리 가 있는 문제는 "세그먼트 트리" 를 이용해 풀어야 한다.
구간 합은 보통 prefix sum(psum) 배열을 이용해 [a, b] 의 구간합을 psum[b] - psum[a-1] 로 풀 수 있다.
하지만 구간 값이 변경되는 "K 개의 수정 쿼리"가 있을 때는, 매 수정마다 N 크기의 배열을 다시 계산해야하기 때문에,
전체 복잡도가 O(K*N) 이 된다.
세그먼트 트리는
Leaf node : 배열 값
Internal node : 자식노드들의 구간 합
을 저장하여, 수정을 O(logN) 만에, 구간 합 계산 또한 O(logN) 번 만에 수행할 수 있는 자료구조이다.
자세한 내용은 백준님 블로그에 설명되어 있다.
이 문제는 값 수정 쿼리가 있는 구간 곱을 계산하는 문제로, 세그먼트 트리를 이용해야하며, 합 대신 곱 연산으로 변경해주면 된다.
#주의할 점
* 곱 연산이기 때문에 발생하는 오버플로우 문제가 있다.
* update 를 하는 방식은 다양하지만, 이전 값과의 차이(difference) 값을 해당 노드마다 곱해주는 방식으로는 WA 를 받는다.
- difference 값을 계산하면서 발생하는 나눗셈 연산이 문제의 조건인 1000000007 MOD 연산에 영향을 줄 수 있을 것 같다.
- 따라서 잎 노드의 변경으로부터 다시 계산하는 방식으로 업데이트를 수행한다.
소스코드
-
#include<stdio.h>
-
#include<vector>
-
#define MOD(x) ((x)%1000000007)
-
using namespace std;
-
typedef unsigned long long ull;
-
int n, m, k;
-
ull arr[1000001];
-
-
ull make_seg_tree(vector< ull > &v, int node, int start, int end){
-
if(start == end){
-
return v[node] = arr[start];
-
}
-
return v[node] = MOD( make_seg_tree(v, node*2, start, (start+end)/2) *
-
make_seg_tree(v, node*2+1, (start+end)/2 + 1, end));
-
}
-
ull update_seg_tree(vector<ull>&v, int node, int start, int end, int idx, ull val, bool was_zero) {
-
if( idx < start || end < idx) return v[node];
-
-
if(start == end) {
-
arr[idx] = val;
-
return v[node] = val;
-
} else {
-
return v[node] = MOD(update_seg_tree(v, node*2, start, (start+end)/2, idx, val, was_zero) *
-
update_seg_tree(v, node*2+1, (start+end)/2+1, end, idx, val, was_zero));
-
}
-
// v[node] = was_zero ? val : MOD((ull)(v[node] / arr[idx] * val)); // difference 를 이용한 수정
-
}
-
-
ull get_mul(vector< ull >&v, int node, int start, int end, int left, int right) {
-
if(right < start || end < left) return 1;
-
if(start==end) return v[node];
-
if(left <= start && end <= right){
-
return v[node];
-
}
-
return MOD( get_mul(v, node*2, start, (start+end)/2, left, right) *
-
get_mul(v, node*2+1, (start+end)/2+1, end, left, right));
-
}
-
-
int main(){
-
scanf("%d %d %d",&n,&m,&k);
-
for(int i=1;i<=n;i++){
-
scanf("%u",&arr[i]);
-
}
-
vector< ull > v(4*n);
-
make_seg_tree(v, 1, 1, n);
-
-
int a, b,c;
-
for(int i=0; i<m+k;i++){
-
scanf("%d %d %d",&a, &b, &c);
-
if(a == 1){
-
//update
-
bool was_zero = arr[b] == 0;
-
ull val = (ull)c;
-
update_seg_tree(v, 1, 1, n, b, val, was_zero);
-
arr[b] = val;
-
} else{
-
//get mul
-
printf("%u\n", get_mul(v, 1, 1, n, b, c));
-
}
-
}
-
-
return 0;
-
}
'알고리즘 문제풀이' 카테고리의 다른 글
BOJ 1194 달이 차오른다, 가자. (0) | 2020.08.11 |
---|---|
BOJ 6087 레이저통신 (0) | 2020.08.09 |
1344 축구 (0) | 2018.06.01 |
1351 무한 수열 (0) | 2018.05.28 |
1670 정상 회담 2 (0) | 2018.05.17 |