给一个序列,接下来有若干条命令
1 L R : 给区间[L,R]之间的每个位置i,加上Fib(i-L+1),Fib(i)表示斐波那契数列第i项
2 L R : 返回区间[L,R]的区间和。
利用斐波那契数列的两个性质,若一个数列满足F(1)=a,F(2)=b,Fi=Fi-2+F(i-1),则有F(n)=a*Fib(n-2)+b*Fib(n-1),且F的前N项和等于F(n+2)-F(2)。
可以发现,对于任何一个形同斐波那契的序列,只要知道前两项,就可以O(1)求出第N项以及前K项和,这样再每次1命令的时候,直接给要修改的区间标上要增加的斐波那契数列的前两项就行,维护子树的时候左子树标记不变,右子树根据左子树中修改的数量,更新标记即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
typedef long long ll;
const int maxn=300000+30;
const ll mod=1e9+9;
ll fib[maxn];
int n,m;
struct Mark
{
ll a,b;
Mark(){}
Mark(ll x,ll y)
{
a=x; b=y;
}
};
ll F(int x,ll a,ll b)
{
return (fib[x-2]%mod*a%mod+fib[x-1]%mod*b%mod)%mod;
}
ll add(ll x,ll y)
{
x+=y%mod;
x=(x%mod+mod)%mod;
return x;
}
struct segmenttree
{
Mark mark[maxn<<2];
ll sum[maxn<<2];
void init()
{
memset(mark,0,sizeof mark);
memset(sum,0,sizeof sum);
}
void pushup(int id)
{
sum[id]=add(sum[id<<1|1],sum[id<<1]);
}
void pushdown(int id,int len)
{
if (mark[id].a==0 && mark[id].b==0) return;
mark[id<<1].a=add(mark[id<<1].a,mark[id].a);
mark[id<<1].b=add(mark[id<<1].b,mark[id].b);
int midd=len-len/2;
sum[id<<1]=add(sum[id<<1],add(F(midd+2,mark[id].a,mark[id].b),-mark[id].b));
ll na=F(midd+1,mark[id].a,mark[id].b);
ll nb=F(midd+2,mark[id].a,mark[id].b);
mark[id<<1|1].a=add(mark[id<<1|1].a,na);
mark[id<<1|1].b=add(mark[id<<1|1].b,nb);
sum[id<<1|1]=add(sum[id<<1|1],add(F(len/2+2,na,nb),-nb));
mark[id].a=mark[id].b=0;
pushup(id);
}
void updata(int L,int R,int id,int l,int r,ll a,ll b)
{
int m=(l+r)>>1;
int len=r-l+1;
if (L==l && R==r)
{
mark[id].a=add(mark[id].a,a);
mark[id].b=add(mark[id].b,b);
sum[id]=add(sum[id],add(F(len+2,a,b),-b));
return;
}
pushdown(id,len);
ll na,nb;
if (R<=m)
{
updata(L,R,lson,a,b);
}
else if (L>m)
{
updata(L,R,rson,a,b);
}
else
{
na=F(m-L+1+1,a,b);
nb=F(m-L+1+2,a,b);
updata(L,m,lson,a,b);
updata(m+1,R,rson,na,nb);
}
pushup(id);
}
ll query(int L,int R,int id,int l,int r)
{
if (L==l && R==r) return sum[id];
int m=(l+r)>>1;
pushdown(id,r-l+1);
if (R<=m) return query(L,R,lson);
else if (L>m) return query(L,R,rson);
else return query(L,m,lson)+query(m+1,R,rson);
}
}sgt;
void init()
{
fib[0]=0;
fib[1]=fib[2]=1;
for (int i=3; i<maxn; i++)
fib[i]=fib[i-1]+fib[i-2],fib[i]%=mod;
}
ll a[maxn];
ll sum[maxn];
int main()
{
init();
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
sgt.init();
memset(sum,0,sizeof sum);
for (int i=1; i<=n; i++) scanf("%I64d",&a[i]);
sum[0]=0;
for (int i=1; i<=n; i++)
sum[i]=sum[i-1]+a[i],sum[i]%=mod;
int x,y,z;
for (int i=0; i<m; i++)
{
scanf("%d%d%d",&x,&y,&z);
if (x==1)
{
sgt.updata(y,z,1,1,n,1,1);
}
else
{
ll tmp=add(sum[z],-sum[y-1]);
cout<<(sgt.query(y,z,1,1,n)+tmp)%mod<<endl;
}
}
}
return 0;
}