題意
給一個數組,值表示第x個斐波那契數。有兩個操作:
區間求和:對區間的值求相應的斐波那契數,然後求和
區間修改:對區間範圍的數都加上y(代表的斐波那契數的下標往後加y個)
假設f[0] = 0,f[1] = 1 ,f[2] = 2 。。。。然後求第k個斐波那契數就相當於把2*2的矩陣[ [1 1] [1 0] ]自乘k-1次,求m[0][0]就是了。
線段樹維護矩陣,lazy標記也是一個矩陣。其他和普通的區間修改線段樹沒啥區別。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
int n,k;
int arr[N];
struct Matrix
{
ll m[2][2];
friend Matrix operator*(const Matrix& a,const Matrix& b){
Matrix t;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
int sum = 0;
for(int k=0;k<2;k++){
sum += (a.m[i][k])*(b.m[k][j])%mod;
t.m[i][j] = sum%mod;
}
}
}
return t;
}
friend Matrix operator+(const Matrix& a,const Matrix& b){
Matrix t;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
t.m[i][j] = (a.m[i][j]+b.m[i][j])%mod;
}
}
return t;
}
void init(){
m[0][0] = m[1][1] = 1;
m[0][1] = m[1][0] = 0;
}
};
struct node
{
int l,r,k;
Matrix sum,lazy;
}tr[N<<2];
Matrix qpow(int k)
{
Matrix ans,a;
memset(ans.m,0,sizeof(ans.m));
for(int i=0;i<2;i++)
ans.m[i][i] = 1;
a.m[0][0] = a.m[1][0] = a.m[0][1] = 1;
a.m[1][1] = 0;
while(k)
{
if(k&1) ans = ans*a;
a = a*a;
k>>=1;
}
return ans;
}
void build(int k,int l,int r)
{
tr[k].l = l; tr[k].r = r; tr[k].sum.init();tr[k].lazy.init();
if(l==r){
tr[k].sum = qpow(arr[l]-1);
return;
}
int mid = (l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
tr[k].sum = tr[k*2].sum + tr[k*2+1].sum;
}
void pushdown(int k)
{
tr[k*2].sum = tr[k*2].sum*tr[k].lazy;
tr[k*2+1].sum = tr[k*2+1].sum*tr[k].lazy;
tr[k*2].lazy = tr[k*2].lazy*tr[k].lazy;
tr[k*2+1].lazy = tr[k*2+1].lazy*tr[k].lazy;
tr[k].lazy.init();
}
void update(int k,int l,int r,Matrix v)
{
if(tr[k].l>=l&&tr[k].r<=r){
tr[k].sum = tr[k].sum*v;
tr[k].lazy = tr[k].lazy*v;
return;
}
pushdown(k);
int mid = (tr[k].l+tr[k].r)/2;
if(l<=mid) update(k*2,l,r,v);
if(r>mid) update(k*2+1,l,r,v);
tr[k].sum = tr[k*2].sum + tr[k*2+1].sum;
}
ll query(int k,int l,int r)
{
if(tr[k].l>=l&&tr[k].r<=r) return tr[k].sum.m[0][0];
pushdown(k);
int mid = (tr[k].l+tr[k].r)/2;
ll res = 0;
if(l<=mid) res = (res + query(k*2,l,r))%mod;
if(r>mid) res = (res + query(k*2+1,l,r))%mod;
tr[k].sum = tr[k*2].sum + tr[k*2+1].sum;
return res;
}
int main()
{
int n,m; scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
build(1,1,n);
while(m--){
int op,x,y;scanf("%d%d%d",&op,&x,&y);
if(op==1){
int t; scanf("%d",&t);
Matrix c = qpow(t);
update(1,x,y,c);
}
else{
printf("%I64d\n",query(1,x,y));
}
}
return 0;
}