首页 > 其他分享 >CF446C(线段树+斐波那契)

CF446C(线段树+斐波那契)

时间:2022-09-04 20:11:48浏览次数:93  
标签:node CF446C 数列 int 线段 斐波 那契

CF446C(线段树+斐波那契数列)

CF链接

洛谷链接

题目大意:

区间加斐波那契数列,区间求和

分析:

一眼鉴定为线段树

难点在于如何打标记,合并和传递标记

对于斐波那契数列有几个性质(下方会给出解释):

性质1:

两个长度相等的斐波那契数列相加之后仍然可以满足斐波那契 \(f_i=f_{i-1}+f_{i-2}\) 的性质(仍然是一个广义斐波那契数列)。

性质2:

通过维护每个斐波那契数列的第一第二项就可以 \(O(1)\) 的获得任意一项的数值和任意 \(i\) 项的前缀和.


对于性质1:

假设有两个斐波那契数列相加
\(1,2,3,5\)
\(13,21,34,55\)
结果为
\(14,23,37,60\)
其任然是一个广义斐波那契数列

对于性质2:

将斐波那契数列每一项进行拆解
\(f_1=f_1\)
\(f_2=f_2\)
\(f_3=f_2+f_1\)
\(f_4=f_3+f_2=2*f_2+f_1\)
\(……\)
\(f_i=f_{i-1}*f_2+f_{i-2}*f_1\)
斐波那契数列每一项都能用第一第二项来表示。

对于任意 \(i\) 的前缀和
设 \(s_1=a,s_2=b\)
有 \(s_i=a*s_{i-2}+b*s_{i-1}\)

维护标记:

维护某一段区间的和,我们可以在线段树每个节点上维护两个数 \(a,b\) 表示第一个数加了多少,第二个数加了多少。求区间和时,只需要套用上面的式子。

代码:

#include<bits/stdc++.h>
#define int  long long
#define MAXN 300860
#define mod 1000000009
using namespace std;

struct T{
    int l,r,node,len,lazy,val;
}t[MAXN<<2];

int n,m,a[MAXN],f[MAXN],op;


void updata(int node){
    t[node].val=(t[node<<1].val+t[node<<1|1].val)%mod;
}


void build(int l,int r,int node){
    if(l==r){
        t[node].val=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,node<<1);
    build(mid+1,r,node<<1|1);
    updata(node);
}

int cal(int a,int b,int k){
    if(k==1)return a;
    if(k==2)return b;
    return (a*f[k-2]%mod+b*f[k-1]%mod)%mod;

}
int getsum(int a,int b,int k){
    if(k==1)return a;
    if(k==2)return(a+b)%mod;
    return (cal(a,b,k+2)-b+mod)%mod;
}

void paint(int node,int l,int r, int aa,int bb){
    t[node].l=(t[node].l+aa)%mod;
    t[node].r=(t[node].r+bb)%mod;
    t[node].val+=getsum(aa,bb,r-l+1);
    t[node].val%=mod;
}

void pushdown(int node,int l,int r,int mid){
    if(!t[node].l)return ;
    paint(node<<1,l,mid,t[node].l,t[node].r);
    int aa=cal(t[node].l,t[node].r,mid+1-l+1);
    int bb=cal(t[node].l,t[node].r,mid+2-l+1);
    paint(node<<1|1,mid+1,r,aa,bb);
    t[node].l=0;
	t[node].r=0;
}



void change(int l,int r,int node,int x,int y){
    if(x<=l&&r<=y){
        paint(node,l,r,f[l-x+1],f[l-x+2]);
        return ;
    }
    int mid=(l+r)>>1;
    pushdown(node,l,r,mid);
    if(x<=mid)change(l,mid,node<<1,x,y);
    if(mid<y)change(mid+1,r,node<<1|1,x,y);
    updata(node);
}

int ask(int l,int r,int node,int x,int y){
    if(x<=l&&r<=y){
        return t[node].val;
    }
    int mid=(l+r)>>1;
    int ans=0;
    pushdown(node,l,r,mid);
    if(x<=mid)ans+=ask(l,mid,node<<1,x,y);
    if(y>mid)ans+=ask(mid+1,r,node<<1|1,x,y);
    return ans%mod;
}



signed main(){
	std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,n,1);
    int x,y,k;
    f[1]=1;
    f[2]=1;
    
	for(int i=3;i<=n+9;i++){//求斐波那契数列 
        f[i]=(f[i-1]+f[i-2])%mod;
    }
    
    for(int i=1;i<=m;i++){
        cin>>op>>x>>y;
        if(op==1){
            change(1,n,1,x,y);
        }
        else{
        cout<<ask(1,n,1,x,y)<<endl;
        }

    }



    return 0;
}

标签:node,CF446C,数列,int,线段,斐波,那契
From: https://www.cnblogs.com/DAIANZE/p/16655879.html

相关文章

  • C2解决斐波那契数列
    此题较为简单,只需定出后一项等于前两项之和即可代码如下1#include<stdio.h>2#defineN1003voidshow(inta[N])//定义一个函数4{5for(inti=1;i<=2......
  • CSP-S模拟1 [斐波那契,数颜色,分组]
    CSP-S模拟1洛谷上原题,不挂题面了。A.斐波那契P3938斐波那契观察上图,可发现规律:一个数的父亲等于这个数减去最大的小于它的斐波那契数。特殊的,如果这个数是斐波那契......
  • CF446C DZY Loves Fibonacci Numbers
    CF446CDZYLovesFibonacciNumbers题目大意在本题中,我们用\(f_i\)来表示第\(i\)个斐波那契数(\(f_1=f_2=1,f_i=f_{i-1}+f_{i-2}(i\ge3)\))。维护一个序列\(a\),长......
  • 矩阵递推斐波那契数列
      斐波那契数列都很熟悉,它满足,\(F_{n}=\begin{cases}1&n\leqslant2\\F_{n-1}+F_{n-2}&n>2\end{cases}\)。因为\(F_n\)从第三项开始是不断的递推下去的,所以......
  • 【python3.8】斐波拉契数列实现
    importtimedefmemoize(f):memo={}defhelper(x):ifxnotinmemo:memo[x]=f(x)returnmemo[x]returnhelper......
  • leetcode 斐波那契数列 javascript实现
    写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项(即F(N))。斐波那契数列的定义如下:F(0)=0,  F(1) =1F(N)=F(N-1)+F(N-2),其中N>1.斐波那契数列由0......
  • 斐波那契数列前1000项
    {1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,57......
  • 剑指 Offer 10- I. 斐波那契数列
    一、题目写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项(即F(N))。斐波那契数列的定义如下:F(0)=0,  F(1) =1F(N)=F(N-1)+F(N-2),其中N>1.斐......
  • 使用JS 递归函数 输出 斐波那契数列 (return 返回值使用时的注意点 )
      functionaee(i){  if(i==0){    return0;  }  if(i==1){    return1;  }  if(i>=2){ ***//......
  • 【笔记】斐波那契数列
    定义\[\largeF_n=\begin{cases}0&n=0\\1&n=1\\F_{n-2}+F_{n-1}&\operatorname{otherwise}.\end{cases}\]通项公式\[\largeF_n=\frac{\left(\frac{1+\sqrt5......