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

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;
}