[CF446C]DZY Loves Fibonacci Numbers——线段树+斐波那契数列 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/82024293

题目大意:

两种操作,区间加上一个斐波那契数列,区间求和。

思路:

考虑用线段树来实现区间加法,但是加上的是一个斐波那契数列,所以加法的标记为一段斐波那契数列。
显然错开的斐波那契数列可能加到线段树的同一个结点,似乎不好合并这个区间拥有的两段斐波那契数列的标记。于是考虑斐波那契数列本身的性质,它是形为 f i = f i 1 + f i 2 这样的序列,我们在一个区间上面维护了两段这样的序列,不难发现这两段满足上述递推的序列在合并了之后还是满足上述递推序列,所以我们只需要变换这个区间的前两项即可。
至于区间的和与前两项的关系以及区间中的任意一项与前两项的关系可以预处理出系数,这样就可以在线段树上实现查询和pushdown了。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("CF446C.in","r",stdin);
    freopen("CF446C.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=3e5+10;
const ll mod=1e9+9;
int n,m;
ll f[maxn],cnt1[maxn],cnt2[maxn],sum1[maxn],sum2[maxn];

void add(ll &_,ll __){_=_+__;if(_>mod)_%=mod;}

struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
    ll f1[maxn<<2],f2[maxn<<2],sum[maxn<<2];
    void build(int rt,int l,int r){
        if(l==r)read(sum[rt]);
        else{
            build(lson),build(rson);
            sum[rt]=(sum[lc]+sum[rc])%mod;
        }
    }
    void pushdown(int rt,int l,int r){
        if(l+1==r)add(sum[lc],f1[rt]),add(sum[rc],f2[rt]);
        else{
            add(f1[lc],f1[rt]); add(f2[lc],f2[rt]);
            ll ff1=(f1[rt]*cnt1[mid+2-l]+f2[rt]*cnt2[mid+2-l])%mod;
            ll ff2=(f1[rt]*cnt1[mid+3-l]+f2[rt]*cnt2[mid+3-l])%mod;
            add(f1[rc],ff1); add(f2[rc],ff2);
            add(sum[lc],(f1[rt]*sum1[mid-l+1]+f2[rt]*sum2[mid-l+1])%mod);
            add(sum[rc],(ff1*sum1[r-mid]+ff2*sum2[r-mid])%mod);
        }
        f1[rt]=f2[rt]=0;
    }
    void update(int rt,int l,int r,int L,int R){
        if(L<=l && r<=R){
            if(l==r)add(sum[rt],f[l-L+1]);
            else{
                add(sum[rt],(f[l-L+1]*sum1[r-l+1]+f[l-L+2]*sum2[r-l+1]));
                add(f1[rt],f[l-L+1]); add(f2[rt],f[l-L+2]);
            }
        }
        else{
            if(f1[rt] || f2[rt])pushdown(rt,l,r);
            if(L<=mid)update(lson,L,R);
            if(R>=mid+1)update(rson,L,R);
            sum[rt]=(sum[lc]+sum[rc])%mod;
        }
    }
    ll query(int rt,int l,int r,int L,int R){
        if(L<=l && r<=R)return sum[rt];
        if(f1[rt] || f2[rt])pushdown(rt,l,r);
        ll ret=0;
        if(L<=mid)ret=(ret+query(lson,L,R))%mod;
        if(R>=mid+1)ret=(ret+query(rson,L,R))%mod;
        return ret;
    }
}T;

void init(){
    read(n); read(m);
    f[1]=f[2]=1;
    REP(i,3,n)f[i]=(f[i-1]+f[i-2])%mod;
    T.build(1,1,n);
    cnt1[1]=cnt2[2]=1;
    sum1[1]=sum1[2]=sum2[2]=1;
    REP(i,3,n){
        cnt1[i]=(cnt1[i-1]+cnt1[i-2])%mod;
        cnt2[i]=(cnt2[i-1]+cnt2[i-2])%mod;
        sum1[i]=(sum1[i-1]+cnt1[i])%mod;
        sum2[i]=(sum2[i-1]+cnt2[i])%mod;
    }
}

void work(){
    int ty,x,y;
    REP(i,1,m){
        read(ty); read(x); read(y);
//      REP(j,1,n)printf("%lld ",T.query(1,1,n,j,j));
//      putchar('\n');
        if(ty==1)T.update(1,1,n,x,y);
        else printf("%lld\n",T.query(1,1,n,x,y));
    }
}

int main(){
    File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/82024293
今日推荐