首页 > 代码库 > [CodeForces - 447E] E - DZY Loves Fibonacci Numbers
[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
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:
- 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.
- 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
4 4
1 2 3 4
1 1 4
2 1 4
1 2 4
2 1 3
17
12
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 }
[CodeForces - 447E] E - DZY Loves Fibonacci Numbers