[CF 446C] DZY Loves Fibonacci Numbers

题目要求维护一个数据结构,支持区间依次加斐波那契数列,区间求和。
一开始我想的是利用斐波那契数列前缀和公式,然后下传,类似于维护一个等差数列,但是很快我就发现这个思路有问题。
但是这个思路其实有用,我们考察一下斐波那契数列的通项公式:
(f_n = frac{1}{sqrt{5}} [(frac{1 + sqrt{5}}{2})^n - (frac{1 - sqrt{5}}{2})^n])

其实斐波那契数列可以看成两个等比数列之差。本题要求取模,所以我们不妨求一下(sqrt{5})在模(10^9+9)意义下的模数,通过抄题解计算可以得到其模数为383008016,然后就可以愉快的维护两个等比数列了。
维护方法比较简单,显然公比一定,只需要下传首项即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<set>
#include<map>
#include<string>
#include<iostream>
#include<queue>
#include<cctype>
using namespace std;

#define A(x) cout << #x << " " << x << endl;
#define AA(x,y) cout << #x << " " << x << #y << " " << y << endl;
#define B cout << "Break" << endl;
#define ll long long
#define inf 1000000000

ll read()
{
	ll c = getchar();
	int x = 0,f = 1;
	while(!isdigit(c))
	{
		if(c == '-') f = -1;
		c = getchar();
	}
	while(isdigit(c))
	{
		x = x * 10 + c - '0';
		c = getchar();
	}
	return f * x;
}
#define N 300010
#define mod 1000000009
ll base1,base2,inv,n,m;
int seq[N];
ll quick_pow(ll a,ll b)
{
	ll ret = 1;
	while(b)
	{
		if(b & 1) ret = ret * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ret % mod;
}
struct Segment_Tree
{
	#define mid (l + r >> 1)
	#define ls x << 1,l,mid
	#define rs x << 1 | 1,mid + 1,r
	ll p[N],tree[N << 2],lazy[N << 2],q,Inv;
	void init()
	{
		p[0] = 1;
		for(ll i = 1;i <= n;++i) p[i] = p[i - 1] * q % mod;
		Inv = quick_pow(q - 1,mod - 2);
		build(1,1,n);
		return;
	}
	void push_up(ll x)
	{
		tree[x] = (tree[x << 1] + tree[x << 1 | 1]) % mod;
		return;
	}
	void build(ll x,ll l,ll r)
	{
		if(l == r) return;
		build(ls);
		build(rs);
		push_up(x);
		return;
	}
	void add(ll x,ll l,ll r,ll a)
	{
		lazy[x] += a;
		tree[x] += (a * p[r - l + 1] % mod - a + mod) % mod * Inv % mod;
		return;
	}
	void push_down(ll x,ll l,ll r)
	{
		if(!lazy[x]) return;
		add(ls,lazy[x]);
		add(rs,lazy[x] * p[r - l + 1] % mod);
		lazy[x] = 0;
	}
	void modify(ll x,ll l,ll r,ll L,ll R,ll a)
	{
		if(l == L && r == R)
		{
			add(x,l,r,a);
			return;
		}
		push_down(x,l,r);
		if(r <= mid) modify(ls,L,R,a);
		else if(l > mid) modify(rs,L,R,a);
		else
		{
			modify(ls,L,mid,a);
			modify(rs,mid + 1,R,a * p[mid - L + 1] % mod);
		}
		push_up(x);
		return;
	}
	ll query(ll x,ll l,ll r,ll L,ll R)
	{
		if(l == L && r == R) return tree[x];
		push_down(x,l,r);
		if(r <= mid) return query(ls,L,R);
		else if(l > mid) return query(rs,L,R);
		else return (query(ls,L,mid) + query(rs,mid + 1,R)) % mod;
	}

}t1,t2;

int main()
{
	t1.q = (383008016 + 1) * quick_pow(2ll,mod - 2) % mod;
	t2.q = (1 - 383008016 + mod) * quick_pow(2ll,mod - 2) % mod;
	inv = quick_pow(383008016,mod - 2);

	n = read(),m = read();
	for(ll i = 1;i <= n;++i) seq[i] = (seq[i - 1] + read()) % mod;
	t1.init(),t2.init();
	while(m--)
	{
		ll op = read(),l = read(),r = read();
		if(op == 1)
		{
			t1.modify(1,1,n,l,r,t1.q);
			t2.modify(1,1,n,l,r,t2.q);
		}
		else
		{
			ll a = t1.query(1,1,n,l,r);
			ll b = t2.query(1,1,n,l,r);
			ll ans = (a - b + mod) % mod * inv % mod;
			printf("%lld
",((seq[r] - seq[l - 1] + mod) % mod + ans) % mod);
		}
	}

}
原文地址:https://www.cnblogs.com/lijilai-oi/p/12408152.html