CF446C DZY Loves Fibonacci Numbers 線段樹

         給一個序列,接下來有若干條命令

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章