题意

维护一个数列,支持区间加,以及区间斐波那契数列数列求和,即i=lrf(ai)\sum_{i=l}^rf(a_i)

解法

首先把f(ai)f(a_i)拆成矩阵的幂次形式: f(ai)=[f(0),f(1)]×[0111](ai1)f(a_i)=[f(0),f(1)]\times \left[\begin{matrix}0&1\\1&1\end{matrix}\right]^{(a_i-1)}

然后用线段树维护右边的矩阵就好。

区间加xx就是区间的和直接乘[0111]x\left[\begin{matrix}0&1\\1&1\end{matrix}\right]^{x},区间求和就直接求和即可。

预处理矩阵的幂次可以加快速度。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN(x) a[x].c
#define ADD(x) a[x].c
#define DEL(x) a[x].d
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 100010
#define MOD 1000000007LL
using namespace std;
int n,m;
struct node{
    long long val[2][2];
    inline void clean(){
        for(int i=0;i<=1;i++)for(int j=0;j<=1;j++)val[i][j]=(i==j);
    }
    friend node operator +(const node x,const node y){
        node ret;
        for(int i=0;i<=1;i++)for(int j=0;j<=1;j++)ret.val[i][j]=(x.val[i][j]+y.val[i][j])%MOD;
        return ret;
    }
    friend node operator *(const node x,const node y){
        node ret;
        for(int i=0;i<=1;i++)for(int j=0;j<=1;j++){
            ret.val[i][j]=0;
            for(int k=0;k<=1;k++)ret.val[i][j]=(ret.val[i][j]+x.val[i][k]*y.val[k][j]%MOD)%MOD;
        }
        return ret;
    }
    friend bool operator ==(const node x,const node y){
        for(int i=0;i<=1;i++)for(int j=0;j<=1;j++)if(x.val[i][j]!=y.val[i][j])return false;
        return true;
    }
}null,one,power[35];
struct Segment_Tree{
    node data,c;
    int l,r;
}a[MAXN<<2];
inline long long read(){
    long long date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
long long mexp(long long a,long long b,long long c){
    long long s=1;
    while(b){
        if(b&1)s=s*a%c;
        a=a*a%c;
        b>>=1;
    }
    return s;
}
node pow(long long k){
    node s;
    s.clean();
    for(int i=0;k;i++,k>>=1)if(k&1)s=s*power[i];
    return s;
}
void build(){
    null.val[0][0]=null.val[0][1]=null.val[1][0]=null.val[1][1]=0;
    one.clean();
    power[0].val[0][0]=0;power[0].val[0][1]=power[0].val[1][0]=power[0].val[1][1]=1;
    for(int i=1;i<=32;i++)power[i]=power[i-1]*power[i-1];
}
inline void pushup(int rt){
    DATA(rt)=DATA(LSON)+DATA(RSON);
}
inline void pushdown(int rt){
    if(LSIDE(rt)==RSIDE(rt)||SIGN(rt)==one)return;
    SIGN(LSON)=SIGN(LSON)*SIGN(rt);
    DATA(LSON)=DATA(LSON)*SIGN(rt);
    SIGN(RSON)=SIGN(RSON)*SIGN(rt);
    DATA(RSON)=DATA(RSON)*SIGN(rt);
    SIGN(rt).clean();
}
void buildtree(int l,int r,int rt){
    LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt).clean();
    if(l==r){
        int k=read();
        if(k>1)DATA(rt)=pow(k-1);
        else DATA(rt).clean();
        return;
    }
    int mid=l+r>>1;
    buildtree(l,mid,LSON);
    buildtree(mid+1,r,RSON);
    pushup(rt);
}
void update(int l,int r,const node c,int rt){
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
        SIGN(rt)=SIGN(rt)*c;
        DATA(rt)=DATA(rt)*c;
        return;
    }
    pushdown(rt);
    int mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)update(l,r,c,LSON);
    if(mid<r)update(l,r,c,RSON);
    pushup(rt);
}
node query(int l,int r,int rt){
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    node ans=null;
    pushdown(rt);
    int mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)ans=ans+query(l,r,LSON);
    if(mid<r)ans=ans+query(l,r,RSON);
    return ans;
}
void work(){
    int f,x,l,r;
    while(m--){
        f=read();l=read();r=read();
        if(f==1){
            x=read();
            update(l,r,pow(x),1);
        }
        else if(f==2)printf("%lld\n",query(l,r,1).val[1][1]);
    }
}
void init(){
    n=read();m=read();
    build();
    buildtree(1,n,1);
}
int main(){
    init();
    work();
    return 0;
}