假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]。

写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a。 f[n] 是斐波那契数列

也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少

通过简单的公式叠加也能求和

F[n]  = f[n - 1] * b + f[n - 2] * a

F[n - 1] = f[n - 2] * b + f[n - 3] * a

.....

F[3] = f[2] * b + f[1] * a

F[2] = 1 * b    +        0

F[1] =    0       +        a

令G[n] = 0 + 1 + f[2] + f[3] + .... + f[n - 1]

K[n]  = 1 + 0 + f[1] + f[2] + .... f[n - 2] ,那么F[n] = G[n] * b + K[n] * a

线段树结点维护a,b两个延迟标记,分别表示第一个数和第二个数增加了多少

注意在PushDown和update的时候还要通过F[n]  = f[n - 1] * b + f[n - 2] * a计算出右子节点的前两个数应该增加的值

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream> using namespace std;
typedef long long LL; const int maxn = 3e5 + 10;
const int mod = 1e9 + 9;
#define lson idx << 1, l, mid
#define rson idx << 1 | 1, mid + 1, r LL f[maxn], F[maxn], G[maxn];
void init() {
f[1] = G[1] = 1;
F[0] = 1;
F[1] = 1;
for(int i = 2; i < maxn; i++) {
f[i] = (f[i - 1] + f[i - 2]) % mod;
G[i] = (G[i - 1] + f[i]) % mod;
F[i] = (F[i - 1] + f[i - 1]) % mod;
}
// F[i] = 1 + 0 + f[1] + f[2] + f[3] + ....f[i - 1]
// G[i] = 0 + f[1] + f[2] + f[3] + ....f[i]
}
LL sum[maxn << 2];
LL a[maxn << 2], b[maxn << 2];
void PushUp(int idx) {
sum[idx] = (sum[idx << 1] + sum[idx << 1 | 1]) % mod;
}
void build(int idx, int l, int r) {
a[idx] = b[idx] = 0;
if(l == r) {
scanf("%I64d", &sum[idx]);
} else {
int mid = (r + l) >> 1;
build(lson);
build(rson);
PushUp(idx);
}
} void maintain(int idx, int l,int r, int v1, int v2) {
int len = r - l + 1;
a[idx] = (a[idx] + v1) % mod;
b[idx] = (b[idx] + v2) % mod;
sum[idx] = (sum[idx] + G[len - 1] * v2 % mod + F[len - 1] * v1 % mod) % mod;
}
void PushDown(int idx, int l, int r) {
if(a[idx] != 0 || b[idx] != 0) {
int mid = (r + l) >> 1;
maintain(lson, a[idx], b[idx]);
int len = mid - l + 1;
int v1 = (f[len] * b[idx] + f[len - 1] * a[idx]) % mod;
int v2 = (f[len + 1] * b[idx] + f[len] * a[idx]) % mod;
maintain(rson, v1, v2);
a[idx] = b[idx] = 0;
}
}
void update(int idx, int l, int r, int tl, int tr, int v1, int v2) {
if(tl <= l && tr >= r) {
maintain(idx, l, r, v1, v2);
} else {
PushDown(idx, l, r);
int mid = (r + l) >> 1;
if(tl <= mid) update(lson, tl, tr, v1, v2);
if(tr > mid) {
LL h1 = v1, h2 = v2;
if(tl <= mid) {
int len = mid - max(tl,l) + 1;
h1 = (f[len] * v2 + f[len - 1] * v1) % mod;
h2 = (f[len + 1] * v2 + f[len] * v1) % mod;
}
update(rson, tl, tr, h1, h2);
}
PushUp(idx);
}
}
LL query(int idx, int l, int r, int tl, int tr) {
if(tl <= l && tr >= r) return sum[idx];
else {
PushDown(idx, l, r);
int mid = (r + l) >> 1;
LL ans = 0;
if(tl <= mid) ans = (ans + query(lson, tl, tr)) % mod;
if(tr > mid) ans = (ans + query(rson, tl, tr)) % mod;
return ans;
}
}
int main() {
init();
int n, m;
scanf("%d%d", &n, &m);
build(1, 1, n);
for(int i = 1; i <= m; i++) {
int op, l, r;
scanf("%d%d%d", &op, &l, &r);
if(op == 1) update(1, 1, n, l, r, 1, 1);
else {
LL ans = query(1, 1, n, l, r);
printf("%I64d\n", ans);
}
}
return 0;
}

codeforces 446C DZY Loves Fibonacci Numbers 线段树的更多相关文章

  1. ACM学习历程—Codeforces 446C DZY Loves Fibonacci Numbers(线段树 && 数论)

    Description In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence ...

  2. Codeforces 446C DZY Loves Fibonacci Numbers [线段树,数论]

    洛谷 Codeforces 思路 这题知道结论就是水题,不知道就是神仙题-- 斐波那契数有这样一个性质:\(f_{n+m}=f_{n+1}f_m+f_{n}f_{m-1}\). 至于怎么证明嘛-- 即 ...

  3. codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)

    In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...

  4. Codeforces 446-C DZY Loves Fibonacci Numbers 同余 线段树 斐波那契数列

    C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...

  5. Codeforces 446C —— DZY Loves Fibonacci Numbers(线段树)

    题目:DZY Loves Fibonacci Numbers 题意比較简单,不解释了. 尽管官方的题解也是用线段树,但还利用了二次剩余. 可是我没有想到二次剩余,然后写了个感觉非常复杂度的线段树,还是 ...

  6. codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新

    DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d &a ...

  7. Codeforces 446C - DZY Loves Fibonacci Numbers(斐波那契数列+线段树)

    Codeforces 题目传送门 & 洛谷题目传送门 你可能会疑惑我为什么要写 *2400 的题的题解 首先一个很明显的想法是,看到斐波那契数列和 \(10^9+9\) 就想到通项公式,\(F ...

  8. CF446C DZY Loves Fibonacci Numbers 线段树 + 数学

    有两个性质需要知道: $1.$ 对于任意的 $f[i]=f[i-1]+f[i-2]$ 的数列,都有 $f[i]=fib[i-2]\times f[1]+fib[i-1]\times f[2]$ 其中 ...

  9. Codeforces446C DZY Loves Fibonacci Numbers(线段树 or 分块?)

    第一次看到段更斐波那契数列的,整个人都不会好了.事后看了题解才明白了一些. 首先利用二次剩余的知识,以及一些数列递推式子有下面的 至于怎么解出x^2==5(mod 10^9+9),我就不知道了,但是要 ...

随机推荐

  1. Thoughtful function is also good for investigation

    Did you know how many friends in your IM? Some of them you are not familiar with, but your friends c ...

  2. ReactJS学习笔记(二)

    1.Ajax: componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI. /*demo1*/ var Demo1Box=Rea ...

  3. Postgresql-xl 调研

    Postgresql-xl 调研 来历 这个项目的背后是一家叫做stormDB的公司.整个代买基于postgres-xc.开源版本应该是stormdb的一个分支. In 2010, NTT's Ope ...

  4. linux下wps,系统缺失字体:wingdings、wingdings 2、wingdings3

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAArcAAACdCAIAAAAhV8dZAAAgAElEQVR4nOzdd1wT9/8H8OvXfjvtt8

  5. Java开发的命名规范

    Java的命名规范 定义规范的目的是为了使项目的代码样式统一,使程序有良好的可读性,便于日后维护. 1.工程的命名(全用小写字母) 工程的命名一般全用小写字母,单词之间用下划线“_”隔开. 2.包的命 ...

  6. disconf系列【2】——解决zk部署情况为空的问题

    如下图所示,在安装完成之后,发现zk(zookeeper)部署情况为空. 注:承接上篇,环境未发生改变. 1.解决zk没有启动的问题 查看disconf日志,发现zk没有启动. 实际情况是:zk已经启 ...

  7. Buffer Cache

    Buffer Cache Buffer Cache是SGA区中专门用于存放从数据文件中读取的的数据块拷贝的区域.Oracle进程如果发现需要访问的数据块已经在buffer cache中,就直接读写内存 ...

  8. C++使用protobuf传输中间包含\0的字节数组

    The C++ implementation of protocol buffers returns the byte and string types as std::string. This st ...

  9. Html5知识

    <!DOCTYPE> 声明 <!DOCTYPE>声明有助于浏览器中正确显示网页. 网络上有很多不同的文件,如果能够正确声明HTML的版本,浏览器就能正确显示网页内容. doct ...

  10. js 赋值 要用 toString() ; 太坑了。

    js 赋值 要用 toString() ;     太坑了. js 赋值 要用 toString() ;     太坑了. js 赋值 要用 toString() ;     太坑了.