白駿11505号:区間乗を求めます
質問する
題ショートカットキー>白駿11505号:区間乗を求めます
に答える
これはIndexedツリーを用いて解くことができる問題である.もちろん、segment treeで解くこともできます.前述したように、Indexed treeの方が直感的に分かりやすいので、Indexed treeを使用して解きます.この問題を解決するために、最もよく知られているメリットは
A*B mod n = (A mod n * B mod n) mod n
です.したがって、mod演算をいつでも適用してツリーに保存できます!#include<iostream>
#include<vector>
#define MOD 1000000007
using namespace std;
int N, M, K, num, a, b, c, tsize=1;
vector<long long> IDT;
void init(){ // 앞서 초기화한 leaf node 값을 가지고 internal node들을 '구간곱 % MOD'로 채워 나감
for(int i=tsize-1; i>0; i--)
IDT[i] = (IDT[i<<1]*IDT[(i<<1)|1])%MOD;
}
void update(int idx, int val){
idx+=(tsize-1); // tree에 알맞는 index로 변환
IDT[idx] = val; // b번째 값을 c로 update
while ((idx>>=1)>0){ // 조상들도 update
IDT[idx] = (IDT[idx<<1]*IDT[(idx<<1)|1])%MOD;
}
}
long long section_mul(int left, int right){
left+=(tsize-1); right+=(tsize-1); // tree에 알맞는 index로 변환
long long ans = 1;
while (left<=right){ // 구간 곱을 구함
if((left&1)==1) ans = (ans*IDT[left])%MOD; // tree의 right일 때 값을 취함
if((right&1)==0) ans = (ans*IDT[right])%MOD; // tree의 left일 때 값을 취함
left = (left+1)>>1; // (left+1)/2 node로 이동
right = (right-1)>>1; // (right-1)/2 node로 이동
}
return ans;
}
int main(){
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> N >> M >> K;
while (tsize<N) tsize<<=1; // tree size를 구하기 위해 N보다 크면서 N과 가장 가까운 2의 거듭제곱을 구함
IDT.resize(tsize<<1); // tree size 설정
for(int i=1; i<=IDT.size(); i++) IDT[i]=1; // 곱셈을 위해 IDT의 모든 값을 1로 초기화
for(int i=tsize; i<tsize+N; i++){ // tree의 leaf node들을 입력 값으로 채움
cin>>num;
IDT[i] = num;
}
init(); // IDT를 만듦
for(int i=0; i<M+K; i++){
cin >> a >> b >> c;
if(a==1) update(b, c); // b번째 값을 c로 바꿈
else if(a==2) cout << section_mul(b, c) << '\n'; // [b, c] 구간곱 출력
}
}
Reference
この問題について(白駿11505号:区間乗を求めます), 我々は、より多くの情報をここで見つけました https://velog.io/@danbibibi/백준-11505번-구간-곱-구하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol