线段树维护矩阵信息。。一定要把初值都赋好。。。
因为矩阵具有结合律,所以可以把子矩阵相加作为上一层的矩阵,对于更新的加值x,先在线段树外将转移矩阵自乘x次,
再添加到线段树里。主要是码的准确。。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define mode 1000000007
using namespace std;
typedef unsigned long long ll;
void read(ll &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
struct node
{
ll f[3][3];
}cs;
struct Tree
{
node val,laz;
}tr[100005*4];
node operator*(node a,node b)
{
node as;
for(int i=1;i<=2;++i)
{
for(int j=1;j<=2;++j)
{
as.f[i][j]=0;
for(int k=1;k<=2;++k)
{
as.f[i][j]+=a.f[i][k]*b.f[k][j]%mode;
as.f[i][j]%=mode;
}
}
}
return as;
}
node ksm(node x,ll y)
{
node www;
www.f[1][1]=1;www.f[1][2]=0;
www.f[2][1]=0;www.f[2][2]=1;
while(y)
{
if(y%2==1)www=www*x;
y=y/2;x=x*x;
}
return www;
}
node gett(ll x)
{
if(x==2)
{
node yu;
yu.f[1][1]=yu.f[2][1]=1;yu.f[1][2]=yu.f[2][2]=0;
return yu;
}
if(x==1)
{
node yu;
yu.f[1][1]=1;yu.f[2][1]=0;yu.f[1][2]=yu.f[2][2]=0;
return yu;
}
node ww;
ww.f[1][1]=1,ww.f[1][2]=0,ww.f[2][1]=1,ww.f[2][2]=0;
return ksm(cs,x-2)*ww;
}
void pushup(int rt)
{
tr[rt].val.f[1][1]=(tr[rt<<1].val.f[1][1]+tr[rt<<1|1].val.f[1][1])%mode;
tr[rt].val.f[1][2]=(tr[rt<<1].val.f[1][2]+tr[rt<<1|1].val.f[1][2])%mode;
tr[rt].val.f[2][1]=(tr[rt<<1].val.f[2][1]+tr[rt<<1|1].val.f[2][1])%mode;
tr[rt].val.f[2][2]=(tr[rt<<1].val.f[2][2]+tr[rt<<1|1].val.f[2][2])%mode;
}
void biuld(int l,int r,int rt)
{
tr[rt].laz.f[1][1]=1;tr[rt].laz.f[1][2]=0;
tr[rt].laz.f[2][1]=0;tr[rt].laz.f[2][2]=1;
if(l==r)
{
ll xx;
read(xx);
tr[rt].val=gett(xx);
return;
}
int mid=(l+r)/2;
biuld(l,mid,rt<<1);
biuld(mid+1,r,rt<<1|1);
pushup(rt);
}
void pushdown(int rt)
{
//if(tr[rt].laz)
tr[rt<<1].val=tr[rt].laz*tr[rt<<1].val;
tr[rt<<1|1].val=tr[rt].laz*tr[rt<<1|1].val;
tr[rt<<1].laz=tr[rt].laz*tr[rt<<1].laz;
tr[rt<<1|1].laz=tr[rt].laz*tr[rt<<1|1].laz;
tr[rt].laz.f[1][1]=1;tr[rt].laz.f[1][2]=0;
tr[rt].laz.f[2][1]=0;tr[rt].laz.f[2][2]=1;
}
void insert(int L,int R,int rt,int l,int r,node v)
{
if(L<=l&&r<=R)
{
tr[rt].val=v*tr[rt].val;
tr[rt].laz=v*tr[rt].laz;
return;
}
pushdown(rt);
int mid=(l+r)/2;
if(L<=mid)insert(L,R,rt<<1,l,mid,v);
if(R>mid)insert(L,R,rt<<1|1,mid+1,r,v);
pushup(rt);
}
ll query(int L,int R,int rt,int l,int r)
{
if(L<=l&&r<=R)return tr[rt].val.f[1][1];
pushdown(rt);
int mid=(l+r)/2;
if(R<=mid)return query(L,R,rt<<1,l,mid)%mode;
else if(L>mid)return query(L,R,rt<<1|1,mid+1,r)%mode;
else return (query(L,R,rt<<1,l,mid)+query(L,R,rt<<1|1,mid+1,r))%mode;
}
ll n,m,opt,l1,r1;ll po1;
int main()
{
read(n);read(m);
cs.f[1][1]=1,cs.f[1][2]=1,cs.f[2][1]=1;cs.f[2][2]=0;
biuld(1,n,1);
for(int i=1;i<=m;++i)
{
read(opt);
if(opt==2)
{
read(l1);read(r1);
printf("%I64d\n",query(l1,r1,1,1,n));
}else
{
read(l1);read(r1);read(po1);
node wq=ksm(cs,po1);
insert(l1,r1,1,1,n,wq);
}
}
return 0;
}