题目
思路
看见区间操作比较容易联想到线段树
考虑怎么对于一个节点进行快速计算
对于叶子节点,存下\(f_{a_i-1},f_{a_i}\),每一个节点表示\(\sum_{i=l}^{r}f_{a_i-1},\sum_{i=l}^{r}f_{a_i}\)
考虑对\(a_l到a_r\)进行加\(x\)的操作,其实也就相当于他们合起来之后再进行操作,因为\(f_i=f_{i-1}+f_{i-2}\)
我们将所有的\(f_{i-1}\)看做一个整体,\(f_{i-2}\)看做一个整体,
之后就是快速幂的事情了
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7;
namespace IO
{
void read(int &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void read(long long &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void write(int x)
{
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
void write(long long x)
{
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
}
namespace lst
{
struct mat
{
int n,m;
long long a[3][3];
mat()
{
n=m=0;
memset(a,0,sizeof(a));
}
friend mat operator + (const mat &a,const mat &b)
{
mat c;
c.n=a.n;
c.m=a.m;
for(int i=1;i<=a.n;i++)
for(int j=1;j<=a.m;j++)
c.a[i][j]=(a.a[i][j]+b.a[i][j])%mod;
return c;
}
friend mat operator * (const mat &a,const mat &b)
{
mat c;
c.n=a.n;
c.m=b.m;
for(int i=1;i<=a.n;i++)
for(int k=1;k<=a.m;k++)
for(int j=1;j<=b.m;j++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
return c;
}
void pr()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<<a[i][j]<<' ';
cout<<endl;
}
}
}bas,now,acc;
struct tree
{
int l,r;
mat f;//f_{x-1},f_{x}
mat lazy;
}tre[400005];
mat qkpow(mat a,long long b)
{
if(b==0)
return bas;
if(b==1)
return a;
mat t=qkpow(a,b/2);
t=t*t;
if(b%2==1)
t=t*a;
return t;
}
void push_down(int k)
{
tre[k<<1].f=tre[k].lazy*tre[k<<1].f;
tre[k<<1].lazy=tre[k].lazy*tre[k<<1].lazy;
tre[k<<1|1].f=tre[k].lazy*tre[k<<1|1].f;
tre[k<<1|1].lazy=tre[k].lazy*tre[k<<1|1].lazy;
tre[k].lazy=bas;
}
void build(int l,int r,int k)
{
tre[k].l=l;
tre[k].r=r;
tre[k].lazy=bas;
if(l==r)
{
int x;
cin>>x;
tre[k].f.n=2;
tre[k].f.m=1;
tre[k].f.a[1][1]=1;
tre[k].f.a[2][1]=0;
tre[k].f=qkpow(acc,x)*tre[k].f;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
tre[k].f=tre[k<<1].f+tre[k<<1|1].f;
}
void add(int l,int r,int k=1)
{
if(l>tre[k].r||tre[k].l>r)
return;
if(l<=tre[k].l&&tre[k].r<=r)
{
tre[k].f=now*tre[k].f;
tre[k].lazy=now*tre[k].lazy;
return;
}
push_down(k);
add(l,r,k<<1);
add(l,r,k<<1|1);
tre[k].f=tre[k<<1].f+tre[k<<1|1].f;
}
long long ask(int l,int r,int k=1)
{
if(tre[k].l>r||l>tre[k].r)
return 0;
if(l<=tre[k].l&&tre[k].r<=r)
return tre[k].f.a[2][1];
push_down(k);
return (ask(l,r,k<<1)+ask(l,r,k<<1|1))%mod;
}
}
using namespace IO;
using namespace lst;
int n,m;
int opt,l,r;
long long x;
void init()
{
bas.n=bas.m=2;
for(int i=1;i<=2;i++)
bas.a[i][i]=1;
acc.n=acc.m=2;
acc.a[1][2]=acc.a[2][1]=acc.a[2][2]=1;
}
int main()
{
init();
cin>>n>>m;
build(1,n,1);
for(int i=1;i<=m;i++)
{
read(opt);
read(l);
read(r);
if(opt==1)
{
read(x);
now=qkpow(acc,x);
add(l,r);
}
else
{
write(ask(l,r));
putchar('\n');
}
}
return 0;
}