题意:给你长度为n的数列,有两个操作
①将区间[L,R]加上从1,1为前两项的斐波那契数列。
②询问区间[L,R]的和。
题解:首先肯定是用线段树维护区间和,但是直接加上斐波那契数列又很难维护,所以我们可以利用斐波那契数列的性质:
①我们可以通过标记记录该区间所加的斐波那契的前两项,因为斐波那契相叠加还是斐波那契数列。
②通过前两项,我们可以O(1)的计算出区间和,如下:
但是如何知道第n+2项呢?当我们知道前两项a1和a2的时候,我们可以通过:a*fib[n-2]+b*fib[n-1](fib[i]是以1,1为前两项的斐波那契数列)得到第n+2项,我们预处理所有需要的斐波那契数,也就可以O(1)计算出区间加上的斐波那契数列的和。
AC代码:
#include<stdio.h> #define N 300005 #define mod 1000000009 typedef long long ll; ll fib[N],a[N]; ll tree[N*4],fir[N*4],sec[N*4]; void build(ll L,ll R,ll root) { if(L==R) { tree[root]=a[L]; return ; } ll mid=L+R>>1; build(L,mid,root<<1); build(mid+1,R,root<<1|1); tree[root]=(tree[root<<1]+tree[root<<1|1])%mod; } ll get(ll a1,ll a2,ll n) { if(n==1)return a1%mod; if(n==2)return a2%mod; return ((a1*fib[n-2])%mod+(a2*fib[n-1])%mod)%mod; } ll getsum(ll a,ll b,ll n) { if(n==1)return a%mod; if(n==2)return (a+b)%mod; return (get(a,b,n+2)-get(a,b,2)+mod)%mod; } void pushdown(ll root,ll L,ll R) { ll mid=L+R>>1; tree[root<<1]=(tree[root<<1]+getsum(fir[root],sec[root],mid-L+1))%mod; tree[root<<1|1]=(tree[root<<1|1]+getsum(get(fir[root],sec[root],mid-L+2),get(fir[root],sec[root],mid-L+3),R-mid))%mod; fir[root<<1]=(fir[root<<1]+fir[root])%mod; sec[root<<1]=(sec[root<<1]+sec[root])%mod; fir[root<<1|1]=(fir[root<<1|1]+get(fir[root],sec[root],mid-L+2))%mod; sec[root<<1|1]=(sec[root<<1|1]+get(fir[root],sec[root],mid-L+3))%mod; fir[root]=sec[root]=0; } void update(ll l,ll r,ll L,ll R,ll root,ll a,ll b) { if(l<=L&&R<=r) { tree[root]=(tree[root]+getsum(a,b,R-L+1))%mod; fir[root]=(fir[root]+a)%mod; sec[root]=(sec[root]+b)%mod; return ; } ll mid=L+R>>1; if(fir[root]||sec[root])pushdown(root,L,R); if(r<=mid)update(l,r,L,mid,root<<1,a,b); else if(l>mid)update(l,r,mid+1,R,root<<1|1,a,b); else { update(l,mid,L,mid,root<<1,a,b); update(mid+1,r,mid+1,R,root<<1|1,get(a,b,mid-l+2),get(a,b,mid-l+3)); } tree[root]=(tree[root<<1]+tree[root<<1|1])%mod; } ll query(ll l,ll r,ll L,ll R,ll root) { if(l<=L&&R<=r)return tree[root]; ll mid=L+R>>1; if(fir[root]||sec[root])pushdown(root,L,R); if(r<=mid)return query(l,r,L,mid,root<<1); else if(l>mid)return query(l,r,mid+1,R,root<<1|1); else return (query(l,mid,L,mid,root<<1)+query(mid+1,r,mid+1,R,root<<1|1))%mod; } int main() { fib[1]=fib[2]=1; for(ll i=3;i<N;i++) fib[i]=(fib[i-1]+fib[i-2])%mod; ll n,m; scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,n,1); while(m--) { ll op,l,r; scanf("%lld%lld%lld",&op,&l,&r); if(op==1)update(l,r,1,n,1,1,1); else printf("%lld\n",query(l,r,1,n,1)); } }