码迷,mamicode.com
首页 > 其他好文 > 详细

题解 CF446C 【DZY Loves Fibonacci Numbers】

时间:2020-02-01 16:21:14      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:its   长度   int   查询   修改   mod   用两个   names   数加   

# 题解 CF446C
这是一道数据结构题。

我们先翻译下题目:

给你一个n,给你一个长度为n的序列,给你一个m,给你m此操作,包括区间修改和查询,修改为在一个区间内每个数加上他所对应的斐波那契数,查询为查询区间和。

一看到区间修改和区间查询,我们就可以知道这是一道线段树的题目(不要问我怎么知道的,~~我也想知道~~)

进入正题:

我们一定要找到一种方法,维护区间和。

我们可以先把斐波那契数列的每一项拆开,找规律,我们会发现:

$$f_1=f_1,f_2=f_2$$
$$f_3=f_1+f_2,f_4=f_1+2*f_2$$
$$f_5=2*f_1+3*f_2,f_6=3*f_1+5*f_2$$

我们可以找到规律

$$f_i=f_{i-1}*f_2+f_{i-2}*f_1$$

因为在区间内加入一个斐波那契数列,这个区间任然满足斐波那契数列的关系,只是$f_1$和$f_2$变了而已,所以,我们可以用{a}来维护这个斐波那契数列,即可表示为:

$$a_i=f_{i-1}*a_2+f_{i-2}*a_1$$

因为是维护区间和,所以我们需要累加和,故,我们再将式子拆开,可以得到:

$$s_3=2*a_1+2*a_2$$
$$s_4=3*a_1+4*a_2$$
$$s_5=5*a_1+7*a_2$$

经过观察和归纳,我们可以发现:

$$\sum_ {i=1}^n a_i = f_n*a_1+(f_{n+1}-1)*a_2$$

于是我们就可一开始做这道题了。

我们用两个懒惰标记,分别为$f1$和$f2$,来维护某一段区间的和,当我们要求这段区间的和时,我们只要用上面那个公式求出区间和,然后加入值中就行了。

---------------------------------------------------我是~~超级可爱~~的分割线-------------------------------------------------

代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=300009;
const ll P=1e9+9;
int n,m;
ll f[N];
struct Segtree
{
ll v,f1,f2;
}tree[N<<2];
inline ll read()
{
ll x=0,flag=1;
char ch=getchar();
while(ch>‘9‘||ch<‘0‘) {if(ch==‘-‘) ch=getchar();flag=-1;}
while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
return x*flag;
}
void build(int k,int l,int r)
{
if(l==r)
{
tree[k].v=read();
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
tree[k].v%=P;
}
void push_down(int k,int l,int r) //标记下传
{
if(!(tree[k].f1==0 && tree[k].f2==0))
{
int mid=(l+r)>>1;
tree[k<<1].f1+=tree[k].f1;
tree[k<<1].f1%=P;
tree[k<<1].f2+=tree[k].f2;
tree[k<<1].f2%=P;
tree[k<<1].v+=tree[k].f2*(f[mid-l+2]-1)+tree[k].f1*f[mid-l+1];
tree[k<<1].v%=P;
int pos=mid-l+2;
tree[k<<1|1].f1+=f[pos-1]*tree[k].f2+f[pos-2]*tree[k].f1;
tree[k<<1|1].f1%=P;
tree[k<<1|1].f2+=f[pos]*tree[k].f2+f[pos-1]*tree[k].f1;
tree[k<<1|1].f2%=P;
tree[k<<1|1].v+=tree[k].f2*(f[r-l+2]-1)+tree[k].f1*f[r-l+1]-tree[k].f2*(f[mid-l+2]-1)-tree[k].f1*f[mid-l+1];
tree[k<<1|1].v%=P;
tree[k].f1=0,tree[k].f2=0;
}
}
void modify(int k,int l,int r,int x,int y)
{
if(l>y || r<x) return;
if(l>=x && r<=y)
{
tree[k].f1+=f[l-x+1];
tree[k].f1%=P;
tree[k].f2+=f[l-x+2];
tree[k].f2%=P;
tree[k].v+=f[r-l+1]*f[l-x+1]%P+(f[r-l+2]-1)*f[l-x+2]%P;
tree[k].v%=P;
return;
}
int mid=(l+r)>>1;
push_down(k,l,r);
modify(k<<1,l,mid,x,y);
modify(k<<1|1,mid+1,r,x,y);
tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
tree[k].v%=P;
}
void init()
{
f[1]=1,f[2]=1;
for(int i=3;i<=n+1;i++) f[i]=f[i-1]+f[i-2],f[i]%=P;
}
ll query(int k,int l,int r,int x,int y)
{
if(l>y || r<x) return 0;
if(l>=x && r<=y) return tree[k].v;
push_down(k,l,r);
int mid=(l+r)>>1;
return (query(k<<1,l,mid,x,y)+query(k<<1|1,mid+1,r,x,y))%P;
}

int main()
{
n=read();m=read();
build(1,1,n);
init();
for(int i=1;i<=m;i++)
{
int t=read(),x=read(),y=read();
if(t==1) modify(1,1,n,x,y);
else printf("%lld\n",(query(1,1,n,x,y)%P+P)%P);
}
return 0;
}
```

~~垃圾数据结构~~

题解 CF446C 【DZY Loves Fibonacci Numbers】

标签:its   长度   int   查询   修改   mod   用两个   names   数加   

原文地址:https://www.cnblogs.com/qshjydzh/p/12248586.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!