给出一串数,要求支持以下两个操作:
1.区间加
2.区间查询f(a[i])的和,f(i)表示斐波那契的第i项的值。
对于求f(i)的值,肯定是利用矩阵快速幂,因此f(i)可以表示为(1 1 \n 1 0)^i,这样区间加p就可以转化为区间乘单位矩阵的p次方,而且矩阵乘法满足分配率,这样就可以用线段树来维护。
维护方法:
每个线段树的结点存两个矩阵(区间f(i)的和和懒惰标记),剩余操作与普通线段树基本相同。
注意:不要记录区间加的数值,因为这样每次下传标记都要进行一次矩阵快速幂,时间复杂度多了一个log。
#include
#include
#define ll long long
#define mid ((l+r)>>1)
#define N 100100
#define M 1000000007
using namespace std;
ll n,m,num[N],tt;
struct Jz
{
ll num[2][2];
Jz()
{
num[0][0]=num[0][1]=num[1][0]=num[1][1]=0;
}
init()
{
num[0][1]=num[1][0]=0;
num[0][0]=num[1][1]=1;
}
Jz operator + (const Jz &u) const
{
ll i,j;
Jz res;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
res.num[i][j]=num[i][j]+u.num[i][j];
res.num[i][j]%=M;
}
}
return res;
}
Jz operator * (const Jz &u) const
{
ll i,j,k;
Jz res;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
for(k=0;k<2;k++)
{
res.num[i][j]+=num[i][k]*u.num[k][j]%M;
res.num[i][j]%=M;
}
}
}
return res;
}
Jz po(ll u)
{
Jz res,tmp=*this;
res.num[0][0]=res.num[1][1]=1;
for(;u;)
{
if(u&1) res=res*tmp;
tmp=tmp*tmp;
u>>=1;
}
return res;
}
void out()
{
printf("%lld %lld\n%lld %lld\n",num[0][0],num[0][1],num[1][0],num[1][1]);
}
};
Jz dw,tmp;
struct Node
{
ll ls,rs;
Jz jz,lazy;
};
Node node[N<<1];
void build(ll now,ll l,ll r)
{
if(l==r)
{
node[now].jz=dw.po(num[l]);
return;
}
if(l<=mid)
{
node[now].ls=++tt;
build(tt,l,mid);
node[now].jz=node[now].jz+node[node[now].ls].jz;
}
if(midnow].rs=++tt;
build(tt,mid+1,r);
node[now].jz=node[now].jz+node[node[now].rs].jz;
}
}
inline void down(ll now)
{
if(node[now].ls)
{
node[node[now].ls].lazy=node[node[now].ls].lazy*node[now].lazy;
node[node[now].ls].jz=node[node[now].ls].jz*node[now].lazy;
}
if(node[now].ls)
{
node[node[now].rs].lazy=node[node[now].rs].lazy*node[now].lazy;
node[node[now].rs].jz=node[node[now].rs].jz*node[now].lazy;
}
node[now].lazy.init();
}
void add(ll now,ll l,ll r,ll u,ll v)
{
if(l==u&&v==r)
{
node[now].lazy=node[now].lazy*tmp;
node[now].jz=node[now].jz*tmp;
return;
}
down(now);
Jz res;
if(u<=mid)
{
add(node[now].ls,l,mid,u,min(v,mid));
}
if(midnow].rs,mid+1,r,max(mid+1,u),v);
}
if(l<=mid) res=res+node[node[now].ls].jz;
if(midnow].rs].jz;
node[now].jz=res;
}
ll ask(ll now,ll l,ll r,ll u,ll v)
{
if(l==u&&v==r)
{
return node[now].jz.num[1][0];
}
down(now);
ll res=0;
if(u<=mid)
{
res+=ask(node[now].ls,l,mid,u,min(mid,v));
}
if(midnow].rs,mid+1,r,max(u,mid+1),v);
}
return res%M;
}
int main()
{
dw.num[0][0]=dw.num[0][1]=dw.num[1][0]=1;
ll i,j,o,p,q,z;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
}
build(++tt,1,n);
for(i=1;i<=tt;i++) node[i].lazy.init();
for(i=1;i<=m;i++)
{
scanf("%lld",&o);
if(o==1)
{
scanf("%lld%lld%lld",&p,&q,&z);
tmp=dw.po(z);
add(1,1,n,p,q);
}
else
{
scanf("%lld%lld",&p,&q);
printf("%lld\n",ask(1,1,n,p,q));
}
}
}