很神奇的一道題
題意大概就是支持區間加,然後求區間和。。。
區間和的求法是 sigma(i,l,r) f[i] f[i]表示斐波那契序列第i項
例如一個區間的數字是1 2 3 4 5 6
那麼其和爲1+1+2+3+5+8=20
看到數據範圍。。那斐波那契肯定不能離線處理了,只能是用矩陣去算
那我們如果給一個數+x,相當於讓他再乘x次,這樣就可以用線段樹求解了
那麼問題出現了,我們的lazy標記要怎麼打??
不打的話顯然會退化到n^2,打的話這個和可不是一個整體
然而有一個東西叫做。。分配律
對於矩陣A,B,C
A*C+B*C=(A+B)*C
所以我們在線段樹的每個節點上存下當前的一個矩陣總和的話,好像沒什麼毛病?答案那一項也就是我們原來想的那個答案
然後lazy標記我們可以打成是一個轉移矩陣的^x次,這樣我們就可以很輕鬆的Push下去了
(說實話這是第一次做題把矩陣的分配律用進去。。。。。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(ll i=j;i<=k;i++)
#define Dow(i,j,k) for(ll i=k;i>=j;i--)
using namespace std;
ll lson[500001],rson[500001],L[500001],R[500001],a[500001],rt,tot,n,k,ans;
ll mo=1e9+7;
struct mat
{
ll cube[3][3];
mat(){cube[1][1]=cube[2][2]=0;cube[1][2]=cube[2][1]=0;}
mat operator *(const mat &tx)const
{
mat tmp;
For(k,1,2)
For(i,1,2) if(cube[i][k])
For(j,1,2) tmp.cube[i][j]+=(cube[i][k]*tx.cube[k][j])%mo,tmp.cube[i][j]%=mo;
return tmp;
}
mat operator +(const mat &tx)const
{
mat tmp;
For(i,1,2) For(j,1,2) tmp.cube[i][j]=cube[i][j]+tx.cube[i][j],tmp.cube[i][j]%=mo;
return tmp;
}
}tag[500001],sum[500001],one,zero;
inline mat ksm(mat x,ll y){if(y==0) return zero;mat sum=x;y--;for(;y;y/=2){if(y&1)sum=sum*x;x=x*x;}return sum;}
inline void down(ll x)
{
sum[lson[x]]=sum[lson[x]]*tag[x];
sum[rson[x]]=sum[rson[x]]*tag[x];
tag[lson[x]]=tag[lson[x]]*tag[x];
tag[rson[x]]=tag[rson[x]]*tag[x];
tag[x]=zero;
}
inline void build(ll &x,ll l,ll r)
{
x=++tot;
sum[x]=zero;tag[x]=zero;
L[x]=l;R[x]=r;
if(l==r)
{
sum[x]=ksm(one,a[l]-1);
return;
}
ll mid=(l+r)>>1;
build(lson[x],l,mid);build(rson[x],mid+1,r);
sum[x]=sum[lson[x]]+sum[rson[x]];
}
inline void update(ll x,ll l,ll r,mat v)
{
if(l<=L[x]&&R[x]<=r)
{
tag[x]=tag[x]*v;sum[x]=sum[x]*v;
return;
}
down(x);
if(l<=R[lson[x]]) update(lson[x],l,r,v);
if(r>=L[rson[x]]) update(rson[x],l,r,v);
sum[x]=sum[lson[x]]+sum[rson[x]];
}
inline ll query(ll x,ll l,ll r)
{
if(l<=L[x]&&R[x]<=r)
return sum[x].cube[1][1];
down(x);
ll ret=0;
if(l<=R[lson[x]]) ret+=query(lson[x],l,r),ret%=mo;
if(r>=L[rson[x]]) ret+=query(rson[x],l,r),ret%=mo;
sum[x]=sum[lson[x]]+sum[rson[x]];
return ret;
}
int main()
{
one.cube[1][1]=one.cube[1][2]=one.cube[2][1]=1;one.cube[2][2]=0;
zero.cube[1][1]=zero.cube[2][2]=1;zero.cube[1][2]=zero.cube[2][1]=0;
scanf("%lld%lld",&n,&k);
For(i,1,n) scanf("%lld",&a[i]);
build(rt,1,n);
For(i,1,k)
{
ll opt;
scanf("%lld",&opt);
if(opt==1)
{
ll x,y,v;
scanf("%lld%lld%lld",&x,&y,&v);
mat tmp=ksm(one,v);
update(1,x,y,tmp);
}
else
{
ll x,y;
scanf("%lld%lld",&x,&y);
ans=query(1,x,y);
printf("%lld\n",ans);
}
}
}