题目大意
定义
Fi
表示斐波那契数列的第
i
项。
给定一个长度为
- ′1 L R′ 修改操作,表示给 ai,(L≤i≤R) 加上 Fi−L+1
- ′2 L R′ 询问操作,表示询问 ∑Ri=Lai mod (1e9+9) 的值
Data Constraint
n,m≤105
题解
引入一种算法——定期重构
定期重构
每次的修改操作我们不直接修改而是先将操作存起来,当已经储存了
Size
(一般取
Size=n−−√
)个操作时,再进行修改(重构)。每次查询,先查询已经重构的数组,再遍历已经存储的操作,每个操作单独计算贡献。
非常好证明,时间复杂度是
O(nn−−√)
,运用定期重构可以很好地平衡修改与查询的时间复杂度。
注意到这题,我们的一个修改操作
[L,R]
可以做到
O(1)
,具体来说:
设
Deli
表示第
i
个元素修改后需要加的值,那么对
- DelL=DelL+1
- DelR+1=DelR+1−FR−L+2
- DelR+2=DelR+2−FR−L+1
- ∀i>1,Deli=Deli+Deli−1+Deli−2
这样一来修改就能做到 O(1) 了,但是询问还是 O(n) 的。所以我们可以用到上文提到的定期重构来平衡复杂度。问题完美解决。
时间复杂度: O(nn−−√)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;
#define N 100000 + 10
typedef long long ll ;
const int MO = 1e9 + 9 ;
struct Note {
int l , r ;
Note ( int L = 0 , int R = 0 ) { l = L , r = R ; }
} C[N] ;
int F[N] , S[N] ;
int a[N] , sum[N] , del[N] ;
int n , m , top , Size ;
void ReBuild() {
a[1] = (a[1] + del[1]) % MO ;
sum[1] = a[1] ;
for (int i = 2 ; i <= n ; i ++ ) {
del[i] = ((del[i] + del[i-1]) % MO + del[i-2]) % MO ;
a[i] = (a[i] + del[i]) % MO ;
sum[i] = (sum[i-1] + a[i]) % MO ;
}
memset( del , 0 , sizeof(del) ) ;
}
int main() {
scanf( "%d%d" , &n , &m ) ;
Size = sqrt(n) ;
for (int i = 1 ; i <= n ; i ++ ) {
scanf( "%d" , &a[i] ) ;
sum[i] = (sum[i-1] + a[i]) % MO ;
}
F[1] = F[2] = 1 ;
S[1] = 1 , S[2] = 2 ;
for (int i = 3 ; i <= n ; i ++ ) {
F[i] = (F[i-1] + F[i-2]) % MO ;
S[i] = (S[i-1] + F[i]) % MO ;
}
for (int i = 1 ; i <= m ; i ++ ) {
int op , L , R ;
scanf( "%d%d%d" , &op , &L , &R ) ;
if ( op == 1 ) {
C[++top] = Note( L , R ) ;
del[L] = (del[L] + 1) % MO ;
del[R+1] = (del[R+1] - F[R-L+2] + MO) % MO ;
del[R+2] = (del[R+2] - F[R-L+1] + MO) % MO ;
if ( top == Size ) {
ReBuild() ;
top = 0 ;
}
} else {
int ans = (sum[R] - sum[L-1] + MO) % MO ;
for (int i = 1 ; i <= top ; i ++ ) {
if ( C[i].r < L || C[i].l > R ) continue ;
if ( L >= C[i].l && R <= C[i].r ) ans = (ans + (S[R-C[i].l+1] - S[L-C[i].l] + MO) % MO) % MO ;
else if ( C[i].l >= L && C[i].r <= R ) ans = (ans + S[C[i].r-C[i].l+1]) % MO ;
else if ( C[i].l >= L ) ans = (ans + S[R-C[i].l+1]) % MO ;
else ans = (ans + (S[C[i].r-C[i].l+1] - S[L-C[i].l] + MO) % MO) % MO ;
}
printf( "%d\n" , ans ) ;
}
}
return 0 ;
}
以上.