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

Description
In mathematical terms, the sequence F n of Fibonacci numbers is defined by the recurrence relation

F 1 = 1; F 2 = 1; F n = F n - 1 + F n - 2 (n > 2).
DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: a 1, a 2, …, a n. 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 F i - l + 1 to each element a i, 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 a 1, a 2, …, a n (1 ≤ a i ≤ 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.

Examples
Input
4 4
1 2 3 4
1 1 4
2 1 4
1 2 4
2 1 3
Output
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.

Solution
h [ 1 ] = a , h [ 2 ] = b ,   h [ i ] = h [ i − 1 ] + h [ i − 2 ] ( i > 2 ) h[1] = a , h[2] = b, ~h[i] = h[i-1] + h[i-2] (i > 2) h[1]=a,h[2]=b, h[i]=h[i1]+h[i2](i>2), 且称 h 这类数列为类Fibonacci数列
有如下结论:
① h的任意长度相同的两段相加后仍为类Fibonacci数列
h [ i ] = a ∗ f [ i − 2 ] + b ∗ f [ i − 1 ] ( i > 2 ) ( f [ i ] 为 F i b o n a c c i 数 列 ) h[i] = a * f[i-2] + b * f[i-1] (i > 2) (f[i] 为Fibonacci数列) h[i]=af[i2]+bf[i1](i>2)(f[i]Fibonacci)
∑ i = 1 n h [ 2 ] = h [ n + 2 ] − h [ 2 ] ( i > 2 ) \sum ^{n}_{i=1}h\left[ 2\right] =h\left[ n+2\right] -h\left[ 2\right] (i > 2) i=1nh[2]=h[n+2]h[2](i>2)

手算一下即可得到上述结论

于是我们可以通过维护区间的第一项a和第二项b(做为lazy标记),维护加在该区间上的类Fibonacci数列

Code

#include <bits/stdc++.h>
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
const int mod = 1e9 + 9;

struct Segtree{
	int l,r;
	ll a,b,sum;
}t[maxn<<4];

ll a[maxn], f[maxn];
inline void push_up(int rt){
	t[rt].sum = (1ll * t[ls].sum + t[rs].sum) % mod;
}

void build(int rt,int l,int r){
	t[rt].l = l, t[rt].r = r;
	if(l == r) {
		t[rt].sum = a[l];return ;
	}
	int mid = (l + r) >> 1;
	build(ls,l,mid);build(rs,mid+1,r);
	push_up(rt);
}

inline ll cal(ll a,ll b,int k){
	if(k == 1) return a % mod;
	if(k == 2) return b % mod;
	return ((1ll * a * f[k-2]) % mod + (1ll * b * f[k-1]) % mod) % mod;
}

inline ll get_sum(ll a,ll b,int k){
	if(k == 1) return a % mod;
	if(k == 2) return (a + b) % mod;
	return ((1ll * cal(a,b,k+2) - cal(a,b,2))%mod+mod)%mod;
}

inline void modify(int rt,ll a,ll b){
	int k = t[rt].r - t[rt].l + 1;
	t[rt].a = (1ll * t[rt].a + a) % mod, t[rt].b = (1ll * t[rt].b + b) % mod;
	t[rt].sum = (1ll * t[rt].sum + get_sum(a,b,k)) % mod;
}

inline void push_down(int rt){
	if(!t[rt].a) return ;
	int l = t[rt].l ,r = t[rt].r ,mid = (l + r) >> 1;
	ll a = t[rt].a, b = t[rt].b;
	modify(ls,a,b);
	ll aa = cal(a,b,mid-l+2), bb = cal(a,b,mid-l+3);
	modify(rs,aa,bb);
	t[rt].a = t[rt].b = 0;
}

void update(int rt,int L,int R,ll a,ll b){
	int l = t[rt].l, r = t[rt].r;
	if(L <= l && r <= R){
		modify(rt,cal(a,b,l-L+1),cal(a,b,l-L+2));
		return ;
	}
	push_down(rt);
	int mid = (l + r) >> 1;
	if(L <= mid) update(ls,L,R,a,b);
	if(R  > mid) update(rs,L,R,a,b);
	push_up(rt);
}

ll query(int rt,int L,int R){
	int l = t[rt].l, r = t[rt].r;
	if(L <= l && r <= R){
		return t[rt].sum % mod;
	}
	push_down(rt);
	int mid = (l + r) >> 1;
	ll res = 0;
	if(L <= mid) res = (res + 1ll * query(ls,L,R)) % mod;
	if(R  > mid) res = (res + 1ll * query(rs,L,R)) % mod;
	return res % mod;
}

void init(){
	f[1] = f[2] = 1;
	for(int i = 3;i < maxn;++i) f[i] = (1ll * f[i-2] + f[i-1]) % mod;
}
int main() {
	init();
	int n,m;scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
	build(1,1,n);
	while(m--){
		int op,l,r;scanf("%d%d%d",&op,&l,&r);
		if(op == 1) update(1,l,r,f[1],f[2]);
		if(op == 2) printf("%lld\n", query(1,l,r) % mod);
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值