http://codeforces.com/problemset/problem/719/E
像等差数列一样 斐波那契数列也满足可加性 所以每个区间只维护前两项即可 给每个区间项数加x等于对每个点把斐波那契矩阵乘x次 线段树里维护前两项 并把laz标记做成矩阵形式即可
一开始智障 把x当参数传进update 每遇到一次目标区间就要做一次矩阵快速幂 喜获一T
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
const ll M=1000000007;
struct node
{
int l;
int r;
ll f1;
ll f2;
ll laz[2][2];
};
node tree[800010];
ll mat[2][2];
int n,q;
void getmul(ll a[][2],ll b[][2])
{
ll t[2][2];
int i,j,k;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
t[i][j]=0;
for(k=0;k<2;k++)
{
t[i][j]=(t[i][j]+(a[i][k]*b[k][j])%M)%M;
}
}
}
memcpy(a,t,sizeof(t));
}
void quickpow(ll x)
{
ll tmp[2][2];
mat[0][0]=1,mat[0][1]=0;
mat[1][0]=0,mat[1][1]=1;
tmp[0][0]=1,tmp[0][1]=1;
tmp[1][0]=1,tmp[1][1]=0;
while(x>0)
{
if(x%2) getmul(mat,tmp);
x/=2,getmul(tmp,tmp);
}
}
bool judge(ll gou[][2])
{
if(gou[0][0]==1&&gou[0][1]==0&&gou[1][0]==0&&gou[1][1]==1) return true;
else return false;
}
void init(ll gou[][2])
{
gou[0][0]=1,gou[0][1]=0;
gou[1][0]=0,gou[1][1]=1;
}
void pushup(int cur)
{
tree[cur].f1=(tree[2*cur].f1+tree[2*cur+1].f1)%M;
tree[cur].f2=(tree[2*cur].f2+tree[2*cur+1].f2)%M;
}
void pushdown(int cur)
{
ll t1,t2;
if(!judge(tree[cur].laz))
{
t1=((tree[cur].laz[1][0]*tree[2*cur].f2)%M+(tree[cur].laz[1][1]*tree[2*cur].f1)%M)%M;
t2=((tree[cur].laz[0][0]*tree[2*cur].f2)%M+(tree[cur].laz[0][1]*tree[2*cur].f1)%M)%M;
tree[2*cur].f1=t1,tree[2*cur].f2=t2;
getmul(tree[2*cur].laz,tree[cur].laz);
t1=((tree[cur].laz[1][0]*tree[2*cur+1].f2)%M+(tree[cur].laz[1][1]*tree[2*cur+1].f1)%M)%M;
t2=((tree[cur].laz[0][0]*tree[2*cur+1].f2)%M+(tree[cur].laz[0][1]*tree[2*cur+1].f1)%M)%M;
tree[2*cur+1].f1=t1,tree[2*cur+1].f2=t2;
getmul(tree[2*cur+1].laz,tree[cur].laz);
init(tree[cur].laz);
}
}
void build(int l,int r,int cur)
{
ll x;
int m;
tree[cur].l=l;
tree[cur].r=r;
tree[cur].laz[0][0]=1,tree[cur].laz[0][1]=0;
tree[cur].laz[1][0]=0,tree[cur].laz[1][1]=1;
if(l==r)
{
scanf("%lld",&x);
if(x==1) tree[cur].f1=1,tree[cur].f2=1;
else
{
quickpow(x-1);
tree[cur].f1=(mat[1][0]+mat[1][1])%M;
tree[cur].f2=(mat[0][0]+mat[0][1])%M;
}
return;
}
m=(l+r)/2;
build(l,m,2*cur);
build(m+1,r,2*cur+1);
pushup(cur);
}
void update(int pl,int pr,int cur)
{
ll t1,t2;
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
t1=((mat[1][0]*tree[cur].f2)%M+(mat[1][1]*tree[cur].f1)%M)%M;
t2=((mat[0][0]*tree[cur].f2)%M+(mat[0][1]*tree[cur].f1)%M)%M;
tree[cur].f1=t1,tree[cur].f2=t2;
getmul(tree[cur].laz,mat);
return;
}
pushdown(cur);
if(pl<=tree[2*cur].r) update(pl,pr,2*cur);
if(pr>=tree[2*cur+1].l) update(pl,pr,2*cur+1);
pushup(cur);
}
ll query(int pl,int pr,int cur)
{
ll res;
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
return tree[cur].f1;
}
pushdown(cur);
res=0;
if(pl<=tree[2*cur].r) res=(res+query(pl,pr,2*cur))%M;
if(pr>=tree[2*cur+1].l) res=(res+query(pl,pr,2*cur+1))%M;
return res;
}
int main()
{
ll x;
int op,l,r;
scanf("%d%d",&n,&q);
build(1,n,1);
while(q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%lld",&l,&r,&x);
quickpow(x);
update(l,r,1);
}
else
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(l,r,1));
}
}
return 0;
}