[CodeForces - 447E] E - DZY Loves Fibonacci Numbers

E  DZY Loves Fibonacci Numbers

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

F1?=?1; F2?=?1; Fn?=?Fn?-?1?+?Fn?-?2 (n?>?2).

DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of nintegers: a1,?a2,?...,?an. Moreover, there are m queries, each query has one of the two types:

  1. Format of the query "1 l r". In reply to the query, you need to add Fi?-?l?+?1 to each element ai, where l?≤?i?≤?r.
  2. Format of the query "2 l r". In reply to the query you should output the value of  modulo 1000000009 (109?+?9).

Help DZY reply to all the queries.

Input

The first line of the input contains two integers n and m (1?≤?n,?m?≤?300000). The second line contains n integers a1,?a2,?...,?an (1?≤?ai?≤?109) — initial array a.

Then, m lines follow. A single line describes a single query in the format given in the statement. It is guaranteed that for each query inequality 1?≤?l?≤?r?≤?n holds.

Output

For each query of the second type, print the value of the sum on a single line.

Example

Input

4 41 2 3 41 1 42 1 41 2 42 1 3

Output

1712

Note

After the first query, a?=?[2,?3,?5,?7].

For the second query, sum?=?2?+?3?+?5?+?7?=?17.

After the third query, a?=?[2,?4,?6,?9].

For the fourth query, sum?=?2?+?4?+?6?=?12.

题目的大意就是,定义了fib数列前两项F[1]=1,F[2]=1。给出整数n,m,再给出n个数和m项操作。

每个操作包含三个数op,l,r,若op=1,就在[l,r]的区间相应加上F[1,r-l+1](每个数对应着加),若op=2,就将[l,r]中所有数统计和并输出。

首先,我们要知道,fib数列有个特殊的性质_两个fib数列相加,还是fib数列,只是前两项的值变动了而已(从而导致后面的数变动).

那么,根据这个性质,就可以通过累计的方法实现_用线段树进行维护.

首先,我们需要知道一些性质:

设fib[1]=a,fib[2]=b,则fib[n]=fib[n-1]*b+fib[n-2]*a.(可推)

fib[1]+fib[2]+fib[3]+......+fib[n]=fib[n+2]-fib[2].(可推)

通过这两个性质,我们可以巧妙的记录线段树上每一个节点的前两个(fib[1],fib[2])的值,然后计算出这个节点上[L,R],所有数的和.

怎么来?

我们对于每一个线段树上的节点,都记录两个值,ta,tb,分别表示这个区间前两项的值,在更新时,

1 void upt(int now,int fir,int sec,int len){
2     T[now].ta=(T[now].ta+fir)%TT,T[now].tb=(T[now].tb+sec)%TT;
3     T[now].key=((long long)T[now].key+(long long)fir*fib[len]+(long long)sec*fib[len+1]-(long long)sec)%TT;
4 }

其中前两句是将标记累计,最后以句就是顺带计算出这个节点的值.

同时,在pushdown函数中,也要对此进行更新.

 1 void push_down(int now){
 2     if (!T[now].ta&&!T[now].tb) return;
 3     int L=T[now].L,R=T[now].R;
 4     upt(now<<1,T[now].ta,T[now].tb,mid-L+1);
 5     int len=mid-L+1,a,b;
 6     a=((long long)T[now].ta*fib[len-1]+(long long)T[now].tb*fib[len])%TT;
 7     b=((long long)T[now].ta*fib[len]+(long long)T[now].tb*fib[len+1])%TT;
 8     upt(now<<1|1,a,b,R-mid);
 9     T[now].ta=T[now].tb=0;
10 }

其中,对于某个节点的子节点,有两段.一段[L,mid],一段[mid+1,R].

那么更新[L,mid]时,它的前缀和当前节点是一样的,所以不需改动信息,直接下传.

更新[mid+1,R]时,需要重新计算出这段区间前两项的值(这可以用上面说的性质算),然后才能下传.

最后下传完了记得把标记清空.

不过不知道为什么,我的线段树开4,5倍空间会炸,开10倍才不炸,很玄学......

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define mid ((L+R)>>1)
 5 using namespace std;
 6 const int TT=1000000009,maxn=300007;
 7 int n,m,a[maxn],fib[maxn];
 8 struct ST{int L,R,key,ta,tb;}T[maxn*10];
 9 int read(){
10     int x=0; char ch=getchar();
11     while (ch<‘0‘||ch>‘9‘) ch=getchar();
12     while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
13     return x;
14 }
15 void make(int now,int L,int R){
16     T[now].L=L,T[now].R=R;
17     if (L==R){T[now].key=a[L]; return;}
18     make(now<<1,L,mid),make(now<<1|1,mid+1,R);
19     T[now].key=(T[now<<1].key+T[now<<1|1].key)%TT;
20 }
21 void upt(int now,int fir,int sec,int len){
22     T[now].ta=(T[now].ta+fir)%TT,T[now].tb=(T[now].tb+sec)%TT;
23     T[now].key=((long long)T[now].key+(long long)fir*fib[len]+(long long)sec*fib[len+1]-(long long)sec)%TT;
24 }
25 void push_down(int now){
26     if (!T[now].ta&&!T[now].tb) return;
27     int L=T[now].L,R=T[now].R;
28     upt(now<<1,T[now].ta,T[now].tb,mid-L+1);
29     int len=mid-L+1,a,b;
30     a=((long long)T[now].ta*fib[len-1]+(long long)T[now].tb*fib[len])%TT;
31     b=((long long)T[now].ta*fib[len]+(long long)T[now].tb*fib[len+1])%TT;
32     upt(now<<1|1,a,b,R-mid);
33     T[now].ta=T[now].tb=0;
34 }
35 void alter(int now,int aimL,int aimR){
36     int L=T[now].L,R=T[now].R;
37     if (L>aimR||R<aimL) return;
38     if (L>=aimL&&R<=aimR){upt(now,fib[L-aimL+1],fib[L-aimL+2],R-L+1); push_down(now); return;}
39     push_down(now);
40     alter(now<<1,aimL,aimR),alter(now<<1|1,aimL,aimR);
41     T[now].key=(T[now<<1].key+T[now<<1|1].key)%TT;
42 }
43 int seek(int now,int aimL,int aimR){
44     int L=T[now].L,R=T[now].R;
45     if (L>aimR||R<aimL) return 0;
46     if (L>=aimL&&R<=aimR) return T[now].key;
47     push_down(now);
48     return (seek(now<<1,aimL,aimR)+seek(now<<1|1,aimL,aimR))%TT;
49 }
50 int main(){
51     n=read(),m=read(),memset(T,0,sizeof T);
52     for (int i=1; i<=n; i++) a[i]=read();
53     make(1,1,n);
54     fib[0]=0,fib[1]=fib[2]=1;
55     for (int i=3; i<=n+3; i++) fib[i]=(fib[i-1]+fib[i-2])%TT;
56     for (int i=1; i<=m; i++){
57         int tp=read(),L=read(),R=read();
58         if (tp==1) alter(1,L,R);
59         else printf("%d\n",seek(1,L,R));
60     }
61     return 0;
62 }

时间: 2024-07-31 19:24:14

[CodeForces - 447E] E - DZY Loves Fibonacci Numbers的相关文章

codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)

In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 = 1; F2 = 1; Fn = Fn - 1 + Fn - 2 (n > 2). DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: a1, a2, ...,

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

DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-14) Description In mathematical terms, the sequence Fn of Fibonacci numbers is defi

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如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 ..

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

第一次看到段更斐波那契数列的,整个人都不会好了.事后看了题解才明白了一些. 首先利用二次剩余的知识,以及一些数列递推式子有下面的 至于怎么解出x^2==5(mod 10^9+9),我就不知道了,但是要用的时候可以枚举一下,把这些参数求出来之后就题目就可以转化为维护等比数列. 由于前面的常数可以最后乘,所以就等于维护两个等比数列好了. 下面我们来看如何维护一个等比数列.假如我对区间[L,R]的加上1,2,4,8...2^n的话,那么我只需要加一个标记x表示这个区间被加了多少次这样的2^n. 举个例

Codeforces446C - DZY Loves Fibonacci Numbers

Portal Description 给出一个\(n(n\leq3\times10^5)\)个数的序列,进行\(m(m\leq3\times10^5)\)次操作,操作有两种: 给区间\([L,R]\)加上一个斐波那契数列,即\(\{a_L,a_{L+1},...,a_R\} \rightarrow \{a_L+F_1,a_{L+1}+F_2,...,a_R+F_{R-L+1}\}\) 询问区间\([L,R]\)的和,对\(10^9+9\)取模. 斐波那契数列:\(F_1=1,F_2=2\)且满足

Codeforces Round #FF (Div. 2) E. DZY Loves Fibonacci Numbers(斐波那契的定理+线段树)

/* 充分利用了菲波那切数列的两条定理: ①定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[n] = b * fib[n - 1] + a * fib[n - 2](n≥3),其中fib[i]为斐波那契数列的第 i 项. ②定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[1] + F[2] + -- + F[n] = F[n + 2] - b 这题还有一个事实,

【CF446C】DZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)

Description ? 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solution ? 先来考虑一段斐波那契数列如何快速求和,根据性质有 \[ \begin {align} fib_n &= fib_{n - 1} + fib_{n - 2} \ &= fib_ {n - 2} + fib_{n - 3} + fib_{n - 2} \ &= fib_{n -

CF446C DZY Loves Fibonacci Numbers 线段树 + 数学

code: #include <bits/stdc++.h> #define N 400004 #define LL long long #define lson now<<1 #define rson now<<1|1 #define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace

题解 CF446C 【DZY Loves Fibonacci Numbers】

# 题解 CF446C这是一道数据结构题. 我们先翻译下题目: 给你一个n,给你一个长度为n的序列,给你一个m,给你m此操作,包括区间修改和查询,修改为在一个区间内每个数加上他所对应的斐波那契数,查询为查询区间和. 一看到区间修改和区间查询,我们就可以知道这是一道线段树的题目(不要问我怎么知道的,~~我也想知道~~) 进入正题: 我们一定要找到一种方法,维护区间和. 我们可以先把斐波那契数列的每一项拆开,找规律,我们会发现: $$f_1=f_1,f_2=f_2$$$$f_3=f_1+f_2,f_