考虑构造矩阵并利用线段树维护操作,此时不难构造出对应矩阵:

Xi=[aibi1]X_i=\begin{bmatrix}a_i & b_i & 1\end{bmatrix} $$X_i\begin{bmatrix}1 & 0 & 0 \\ v & 1 & 0 \\ 0 & 0 & 1\end{bmatrix} \xrightarrow{\text{Operation 1}}X_i' $$$$X_i\begin{bmatrix}1 & 0 & 0 \\ 0 & v & 0 \\ 0 & 0 & 1\end{bmatrix} \xrightarrow{\text{Operation 3}}X_i' $$$$X_i\begin{bmatrix}1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 0 & 1\end{bmatrix} \xrightarrow{\text{Operation 4}}X_i' $$

操作 2 只需对区间矩阵的和提取第一项即可,至此问题得到解决。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int P=1e9+7;
const int PTA=262144;
struct Square
{
    int n,m;
    int a[4][4];
};
Square operator+(Square a,Square b)
{
    int n=a.n,m=b.m;
    Square c=(Square){n,m,{{}}};
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            c.a[i][j]=a.a[i][j]+b.a[i][j];
            if(c.a[i][j]>=P) c.a[i][j]-=P;
        }
    return c;
}
Square operator*(Square a,Square b)
{
    if(a.m!=b.n) exit(-1);
    int n=a.n,m=a.m,k=b.m;
    Square c=(Square){n,k,{{}}};
    for(int i=1;i<=n;i++)
        for(int j=1;j<=k;j++)
            c.a[i][j]=0;
    for(int l=1;l<=m;l++)
        for(int j=1;j<=k;j++)
            for(int i=1;i<=n;i++)
            {
                c.a[i][j]+=a.a[i][l]*b.a[l][j]%P;
                if(c.a[i][j]>=P) c.a[i][j]-=P;
            }
    return c;
}
const Square S1=(Square){1,3,{{},{0,0,1,1}}};
const Square S3=(Square){3,3,{{},{0,1},{0,0,1},{0,0,0,1}}};
inline Square SQ(int type,int conf)
{
    switch(type)
    {
        case 1: return (Square){3,3,{{},{0,1},{0,conf,1},{0,0,0,1}}};
        case 3: return (Square){3,3,{{},{0,1},{0,0,conf},{0,0,0,1}}};
        case 4: return (Square){3,3,{{},{0,1},{},{0,0,1,1}}};
    }
}
Square aa[530012],all[530012];
int ll[530012],rr[530012];
void init()
{
    for(int i=1;i<=2*PTA-1;i++)
        aa[i]=S3;
    for(int i=1,j=PTA;i<=PTA;i++,j++)
    {
        all[j]=S1;
        ll[j]=rr[j]=i;
    }
    for(int i=PTA-1;i>=1;i--)
    {
        all[i]=all[i+i]+all[i+i+1];
        ll[i]=ll[i+i];
        rr[i]=rr[i+i+1];
    }
}
void add(int type,int conf,int l,int r,int b)
{
    if(ll[b]==l&&rr[b]==r)
    {
        Square c=SQ(type,conf);
        all[b]=all[b]*c;
        aa[b]=aa[b]*c;
        return;
    }
    Square d=aa[b];
    aa[b]=S3;
    aa[b+b]=aa[b+b]*d;
    all[b+b]=all[b+b]*d;
    aa[b+b+1]=aa[b+b+1]*d;
    all[b+b+1]=all[b+b+1]*d;
    if(l<=rr[b+b]) add(type,conf,l,min(r,rr[b+b]),b+b);
    if(r>=ll[b+b+1]) add(type,conf,max(l,ll[b+b+1]),r,b+b+1);
    all[b]=all[b+b]+all[b+b+1];
}
int get(int l,int r,int b)
{
    if(ll[b]==l&&rr[b]==r) return all[b].a[1][1];
    Square d=aa[b];
    aa[b]=S3;
    aa[b+b]=aa[b+b]*d;
    all[b+b]=all[b+b]*d;
    aa[b+b+1]=aa[b+b+1]*d;
    all[b+b+1]=all[b+b+1]*d;
    int ans=0;
    if(l<=rr[b+b]) ans+=get(l,min(r,rr[b+b]),b+b);
    if(r>=ll[b+b+1]) ans+=get(max(l,ll[b+b+1]),r,b+b+1);
    all[b]=all[b+b]+all[b+b+1];
    if(ans>=P) ans-=P;
    return ans;
}
signed main()
{
    init();
    int n,m;
    scanf("%lld %lld",&n,&m);
    while(m--)
    {
        int z,l,r,x;
        scanf("%lld %lld %lld ",&z,&l,&r);
        switch(z)
        {
            case 1:
            {
                scanf("%lld",&x);
                add(1,x,l,r,1);
                break;
            }
            case 2:
            {
                printf("%lld\n",get(l,r,1)%P);
                break;
            }
            case 3:
            {
                scanf("%lld",&x);
                add(3,x,l,r,1);
                break;
            }
            case 4:
            {
                add(4,0,l,r,1);
                break;
            }
        }
    }
    return 0;
}