Lazy Propagation을 이용한 세그먼트 트리로 접근하기에는 피보나치 수의 합을 빠르게 구할 수 없을 것 같습니다.
모든 쿼리를 적용한 후의 결과만 출력하면 되기 때문에 모든 쿼리를 한 번에 처리하는 방법을 떠올리려 했습니다.
이전 항과 다음 항을 이용하여 피보나치 수를 구해나갈 때, $i$번째 항을 계산하는 중 $i = l$인 쿼리가 존재한다면 다음 항 값에 $1 (= F_1)$을 더해줍니다. $i = r$인 쿼리가 존재한다면 이전 항에서 $F_{r - l}$을, 다음 항에서 $F_{r - l + 1}$을 빼 주면 최종 수열을 구해나갈 수 있습니다.
코드
use std::fmt::Write;
use std::io::{stdin, Read};
use std::iter::successors;
const M: usize = 1_000_000_007;
fn main() {
let mut input = String::new();
stdin().read_to_string(&mut input).unwrap();
let mut output = String::new();
let mut input = input.split_ascii_whitespace().map(str::parse).flatten();
let n = input.next().unwrap();
let f: Vec<_> = successors(Some((1usize, 0usize)), |&(p, n)| Some((n, (p + n) % M)))
.map(|(_, n)| n)
.take(n + 1)
.collect();
let q = input.next().unwrap();
let mut events = Vec::with_capacity(q * 2);
for _ in 0..q {
let l = input.next().unwrap();
let r = input.next().unwrap();
events.push((l, 0));
events.push((r, r - l + 1));
}
events.sort_unstable();
let mut prev = 0;
let mut current = 0;
let mut seq = Vec::with_capacity(n);
let mut events = events.iter().peekable();
for i in 1..=n {
while let Some(&&(t, len)) = events.peek() {
if i == t && len == 0 {
events.next();
current += 1;
current %= M;
} else {
break;
}
}
seq.push(current);
while let Some(&&(t, len)) = events.peek() {
if i == t && len > 0 {
events.next();
prev = (prev + M - f[len - 1]) % M;
current = (current + M - f[len]) % M;
} else {
break;
}
}
let temp = current;
current += prev;
current %= M;
prev = temp;
}
for elem in seq {
write!(output, "{} ", elem).ok();
}
print!("{}", output);
}