Problem
DZY Loves Fibonacci Numbers
T i m e l i m i t : 4 S e c \mathrm{Time\;limit:\;4\;Sec} T i m e l i m i t : 4 S e c
M e m o r y l i m i t : 256 M B \mathrm{Memory\;limit:\;256\;MB} M e m o r y l i m i t : 2 5 6 M B
Description
In mathematical terms, the sequence F n F_n F n of F i b o n a c c i Fibonacci F i b o n a c c i n u m b e r s numbers n u m b e r s is defined by the recurrence relation F 1 = 1 , F 2 = 1 , F 3 = F 1 + F 2 = 3 , ⋯ F n = F n − 1 + F n − 2 F_1 = 1,F_2 = 1,F_3=F_1+F_2=3,\cdots F_n = F_{n-1}+F_{n-2} F 1 = 1 , F 2 = 1 , F 3 = F 1 + F 2 = 3 , ⋯ F n = F n − 1 + F n − 2 .
D Z Y \mathrm{DZY} D Z Y loves Fibonacci numbers very much. Today D Z Y \mathrm{DZY} D Z Y gives you an array consisting of n n n integers: a 1 , a 2 , ⋯ , a n a_1, a_2,\cdots,a_n a 1 , a 2 , ⋯ , a n . Moreover, there are m m m queries, each query has one of the two types:
Format of the query “1 1 1 l l l r r r ”. In reply to the query, you need to add F i − l + 1 F_{i-l+1} F i − l + 1 to each element a i a_i a i , where l ≤ i ≤ r l\le i\le r l ≤ i ≤ r .
Format of the query “2 2 2 l l l r r r ”. In reply to the query you should output the value of ∑ i = l r a i \sum_{i=l}^{r}{a_i} ∑ i = l r a i modulo 1 0 9 + 9 10^9+9 1 0 9 + 9 .
Help D Z Y \mathrm{DZY} D Z Y reply to all the queries.
The first line of the input contains two integers n n n and m m m ( 1 ≤ n , m ≤ 3 × 1 0 5 ) (1 \le n, m \le 3\times 10^5) ( 1 ≤ n , m ≤ 3 × 1 0 5 ) . The second line contains n integers a 1 , a 2 , ⋯ , a n ( 1 ≤ a i ≤ 1 0 9 ) a_1, a_2, \cdots, a_n (1 ≤ a_i \le10^9) a 1 , a 2 , ⋯ , a n ( 1 ≤ a i ≤ 1 0 9 ) — initial array a a a .
Then, m m 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 1 \le l \le r \le n 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
1 2 3 4 5 6 4 4 1 2 3 4 1 1 4 2 1 4 1 2 4 2 1 3
Output
Note
After the first query, a = [ 2 , 3 , 5 , 7 ] a = [2, 3, 5, 7] a = [ 2 , 3 , 5 , 7 ] .
For the second query, s u m = 2 + 3 + 5 + 7 = 17 sum = 2 + 3 + 5 + 7 = 17 s u m = 2 + 3 + 5 + 7 = 1 7 .
After the third query, a = [ 2 , 4 , 6 , 9 ] a = [2, 4, 6, 9] a = [ 2 , 4 , 6 , 9 ] .
For the fourth query, s u m = 2 + 4 + 6 = 12 sum = 2 + 4 + 6 = 12 s u m = 2 + 4 + 6 = 1 2 .
标签:线段树
Translation
给出一个长为3 × 1 0 5 3\times 10^5 3 × 1 0 5 级别的初始数组,要求维护两种操作:
将a l ∼ a r a_l \sim a_r a l ∼ a r 中的每个数对应加上从F i b 1 ∼ F i b l − r + 1 Fib_1\sim Fib_{l-r+1} F i b 1 ∼ F i b l − r + 1 的斐波那契数,即使a i ( i ∈ [ l , r ] ) a_i(i\in[l,r]) a i ( i ∈ [ l , r ] ) 加上F i b i − l + 1 Fib_{i-l+1} F i b i − l + 1
询问∑ i = l r a i \sum_{i=l}^{r}{a_i} ∑ i = l r a i 模1 0 9 + 9 10^9+9 1 0 9 + 9 的值
Solution
不难想到此题需要用线段树维护。不过难点在于如何合并标记。
初步想法是每次打标记时记录下此区间是从斐波那契数列的多少项开始一一对应地加进去,不过这样是无法合并标记的,每个结点只能有一个标记,可以被卡成O ( n 2 log n ) O(n^2\log n) O ( n 2 log n ) 。
考虑把标记换一种存法。对于一个数列x 1 = a , x 2 = b , x 3 = a + b , x 4 = a + b × 2 , ⋯ x n = x n − 1 + x n − 2 x_1=a,x_2=b,x_3=a+b,x_4=a+b\times 2,\cdots x_n=x_{n-1}+x_{n-2} x 1 = a , x 2 = b , x 3 = a + b , x 4 = a + b × 2 , ⋯ x n = x n − 1 + x n − 2 ,我们将其称为一个“伪斐波那契数列”,不难发现其等于几个斐波那契数列的子序列之和,即在原题中,不管如何加,每个区间最后加的数列都是一个伪斐波那契数列。而此序列可以仅通过最前面的两项a a a 和b b b 推出后面的任意项以及前若干项之和,即
x n = x n − 1 + x n − 2 = 2 × x n − 2 + x n − 3 = 3 × x n − 3 + 2 × x n − 4 = F i b n − 2 × x 1 + F i b n − 1 × x 2 ∑ i = 1 n x i = x 1 + x 2 + x 3 + ⋯ x n = x 1 + x 2 + x 2 + x 3 + ⋯ + x n − x 2 = x 3 + x 4 + x 4 + x 5 + ⋯ + x n − x 2 = x 5 + x 6 + x 6 + x 7 + ⋯ + x n − x 2 = x n − 2 + x n − 1 + x n − 1 + x n − x 2 = x n + x n + 1 − x 2 = x n + 2 − x 2 \begin{aligned}
x_n &= x_{n-1}+x_{n-2}\\
&= 2\times x_{n-2}+x_{n-3}\\
&= 3\times x_{n-3}+2\times x_{n-4}\\
&= Fib_{n-2}\times x_1+Fib_{n-1}\times x_2\\
\sum_{i=1}^{n}{x_i} &= x_1+x_2+x_3+\cdots x_n\\
&= x_1+x_2+x_2+x_3+\cdots +x_n-x_2\\
&= x_3+x_4+x_4+x_5+\cdots +x_n-x_2\\
&= x_5+x_6+x_6+x_7+\cdots +x_n-x_2\\
&= x_{n-2}+x_{n-1}+x_{n-1}+x_{n}-x_2\\
&= x_n+x_{n+1}-x_2\\
&= x_{n+2}-x_{2}
\end{aligned}
x n i = 1 ∑ n x i = x n − 1 + x n − 2 = 2 × x n − 2 + x n − 3 = 3 × x n − 3 + 2 × x n − 4 = F i b n − 2 × x 1 + F i b n − 1 × x 2 = x 1 + x 2 + x 3 + ⋯ x n = x 1 + x 2 + x 2 + x 3 + ⋯ + x n − x 2 = x 3 + x 4 + x 4 + x 5 + ⋯ + x n − x 2 = x 5 + x 6 + x 6 + x 7 + ⋯ + x n − x 2 = x n − 2 + x n − 1 + x n − 1 + x n − x 2 = x n + x n + 1 − x 2 = x n + 2 − x 2
用这两个公式我们可以O ( 1 ) O(1) O ( 1 ) 计算任意项及前任意项的和。
每个标记为一个数对( a , b ) (a,b) ( a , b ) ,那么合并标记的时候将两个标记的a a a 和b b b 分别相加,得到( a 1 + a 2 , b 1 + b 2 ) (a_1+a_2,b_1+b_2) ( a 1 + a 2 , b 1 + b 2 ) 即可。
总时间复杂度O ( n log n ) O(n\log n) O ( n log n ) 。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> #define MAX_N 1000000 #define mid ((s+t)>>1) #define MOD 1000000009 using namespace std;typedef long long lnt;template <class T >inline void read (T &x) { x = 0 ; int c = getchar (), f = 1 ; for (; !isdigit (c); c = getchar ()) if (c == 45 ) f = -1 ; for (; isdigit (c); c = getchar ()) (x *= 10 ) += f*(c-'0' ); } int n, m; lnt fib[MAX_N+5 ] = {0LL , 1LL };struct node {lnt c, f1, f2;} tr[(MAX_N<<2 )+5 ];lnt fn (lnt f1, lnt f2, int len) {return len == 1 ? f1 : (len == 2 ? f2 : (f1*fib[len-2 ]%MOD+f2*fib[len-1 ]%MOD)%MOD);}lnt sum (lnt f1, lnt f2, int len) {return len == 1 ? f1 : (len == 2 ? (f1+f2)%MOD : (fn (f1, f2, len+2 )-f2+MOD)%MOD);}void updata (int v) {tr[v].c = (tr[v<<1 ].c+tr[v<<1 |1 ].c)%MOD;}void downtag (int v, int s, int t) { if (!tr[v].f1) return ; lnt lf1 = tr[v].f1, lf2 = tr[v].f2, rf1 = fn (lf1, lf2, mid-s+2 ), rf2 = fn (lf1, lf2, mid-s+3 ); (tr[v<<1 ].f1 += lf1) %= MOD, (tr[v<<1 ].f2 += lf2) %= MOD, (tr[v<<1 ].c += sum (lf1, lf2, mid-s+1 )) %= MOD; (tr[v<<1 |1 ].f1 += rf1) %= MOD, (tr[v<<1 |1 ].f2 += rf2) %= MOD, (tr[v<<1 |1 ].c += sum (rf1, rf2, t-mid)) %= MOD; tr[v].f1 = tr[v].f2 = 0 ; } void build (int v, int s, int t) { if (s == t) {read (tr[v].c); return ;} build (v<<1 , s, mid), build (v<<1 |1 , mid+1 , t); updata (v); } void modify (int v, int s, int t, int l, int r) { if (s >= l && t <= r) { (tr[v].f1 += fib[s-l+1 ]) %= MOD, (tr[v].f2 += fib[s-l+2 ]) %= MOD; (tr[v].c += sum (fib[s-l+1 ], fib[s-l+2 ], t-s+1 )) %= MOD; return ; } downtag (v, s, t); if (l <= mid) modify (v<<1 , s, mid, l, r); if (r >= mid+1 ) modify (v<<1 |1 , mid+1 , t, l, r); updata (v); } lnt query (int v, int s, int t, int l, int r) { if (s >= l && t <= r) return tr[v].c; lnt ret = 0 ; downtag (v, s, t); if (l <= mid) (ret += query (v<<1 , s, mid, l, r)) %= MOD; if (r >= mid+1 ) (ret += query (v<<1 |1 , mid+1 , t, l, r)) %= MOD; updata (v); return ret; } void init () {for (int i = 2 ; i <= MAX_N; i++) fib[i] = (fib[i-2 ]+fib[i-1 ])%MOD;}int main () { read (n), read (m), init (), build (1 , 1 , n); while (m--) { int opt, l, r; read (opt), read (l), read (r); if (opt == 1 ) modify (1 , 1 , n, l, r); else printf ("%I64d\n" , query (1 , 1 , n, l, r)); } return 0 ; }