线段树。
线段树维护区间矩阵和,操作都是最简单的线段树。$lazy$标记不要记录乘了几次,直接记录乘了几次之后的矩阵就可以了,不然每次下传的时候再算一遍时间复杂度会提高。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<bitset>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-;
void File()
{
freopen("D:\\in.txt","r",stdin);
freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
char c=getchar(); x=;
while(!isdigit(c)) c=getchar();
while(isdigit(c)) {x=x*+c-''; c=getchar();}
} int mod=1e9+;
const int maxn=;
struct Matrix
{
int A[][]; int R,C;
}s[*maxn],t[*maxn];
int n,m;
Matrix Q,Z,P; Matrix ch(Matrix a,Matrix b)
{
Matrix c;
int i, j, k;
for (i = ; i <= a.R; i++)
for (j = ; j <= b.C; j++){
c.A[i][j]=;
for (k = ; k <= a.C; k++){
LL aa=(LL)a.A[i][k],bb=(LL)b.A[k][j];
LL cc=aa*bb%(LL)mod;
int dd=(int)cc;
c.A[i][j] = (c.A[i][j] + dd)%mod;
}
}
c.R=a.R; c.C=b.C;
return c;
} Matrix pow(LL p)
{
Matrix X,Y; X.R=; X.C=; Y.R=; Y.C=; Y.A[][]=; Y.A[][]=;
Y.A[][]=; Y.A[][]=; X.A[][]=; X.A[][]=;
X.A[][]=; X.A[][]=; while (p)
{
if (p % == ) Y = ch(Y,X);
p = p >> ;
X = ch(X,X);
}
return Y;
} void pushUp(int rt)
{
s[rt].R=; s[rt].C=;
s[rt].A[][]=(s[*rt].A[][]+s[*rt+].A[][])%mod;
s[rt].A[][]=(s[*rt].A[][]+s[*rt+].A[][])%mod;
s[rt].A[][]=(s[*rt].A[][]+s[*rt+].A[][])%mod;
s[rt].A[][]=(s[*rt].A[][]+s[*rt+].A[][])%mod;
} bool check(Matrix x)
{
if(x.A[][]!=) return ;
if(x.A[][]!=) return ;
if(x.A[][]!=) return ;
if(x.A[][]!=) return ;
return ;
} void pushDown(int rt)
{
if(check(t[rt])==) return; s[*rt]=ch(s[*rt],t[rt]); t[*rt]=ch(t[*rt],t[rt]);
s[*rt+]=ch(s[*rt+],t[rt]); t[*rt+]=ch(t[*rt+],t[rt]); t[rt].A[][]=; t[rt].A[][]=;
t[rt].A[][]=; t[rt].A[][]=;
} void build(int l,int r,int rt)
{
t[rt].A[][]=; t[rt].A[][]=;
t[rt].A[][]=; t[rt].A[][]=;
t[rt].R=; t[rt].C=; if(l==r)
{
LL x; scanf("%lld",&x); s[rt].R=; s[rt].C=;
s[rt].A[][]=; s[rt].A[][]=;
s[rt].A[][]=; s[rt].A[][]=; s[rt]=ch(s[rt],pow(x-));
return;
} int m=(l+r)/;
build(l,m,*rt);
build(m+,r,*rt+);
pushUp(rt);
} void update(int L,int R,LL x,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
s[rt]=ch(s[rt],P);
t[rt]=ch(t[rt],P);
return ;
} int m=(l+r)/;
pushDown(rt);
if(L<=m) update(L,R,x,l,m,*rt);
if(R>m) update(L,R,x,m+,r,*rt+);
pushUp(rt);
} void add(Matrix a)
{
Q.A[][]=(Q.A[][]+a.A[][])%mod;
Q.A[][]=(Q.A[][]+a.A[][])%mod;
Q.A[][]=(Q.A[][]+a.A[][])%mod;
Q.A[][]=(Q.A[][]+a.A[][])%mod;
} void get(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) { add(s[rt]); return ; } int m=(l+r)/;
pushDown(rt);
if(L<=m) get(L,R,l,m,*rt);
if(R>m) get(L,R,m+,r,*rt+);
pushUp(rt);
} int main()
{
scanf("%d%d",&n,&m);
build(,n,);
for(int i=;i<=m;i++)
{
int op; scanf("%d",&op);
int L,R; scanf("%d%d",&L,&R);
if(op==)
{
LL x; scanf("%lld",&x);
P=pow(x); update(L,R,x,,n,);
}
else
{
Q.R=; Q.C=; memset(Q.A,,sizeof Q.A);
get(L,R,,n,);
Z.R=; Z.C=; Z.A[][]=; Z.A[][]=;
Z=ch(Z,Q);
printf("%d\n",Z.A[][]);
}
}
return ;
}