codeforces 446C 线段树 + fibnacci

C. DZY Loves Fibonacci Numbers
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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, ..., an. Moreover, there are mqueries, each query has one of the two types:

  1. Format of the query "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 "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.

Sample test(s)
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.

题意,给定一个数列,区间更新,每次加上对应的fibnacci值。

思路,要用到两个定理:

假设正常的fibnacci值为fib[i](指以1 1为开头的数列),则以a,b开头的数列的第k个数为a * fib[k-2] + b * fib[k-1];

以a,b开头的k个数之和为fib[k+2] - fib[2](此处为b)

下面是代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
//#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 21
#define maxn 300005
#define mod 1000000009
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
ll add1[maxn<<2],add2[maxn<<2];
ll fib[maxn];ll sum[maxn<<2];
int n,m;
void init()
{
	fib[0] = 0;
	fib[1] = 1;
	for(int i = 2;i < maxn; i++) fib[i] = (fib[i-1] + fib[i-2]) % mod;
}
ll getFib(ll a,ll b,int k) //求以a,b开头的第k个数
{
	if(k == 1) return a;
	if(k == 2) return b;
	return (a * fib[k-2] + b * fib[k-1]) % mod;
}
ll getFibsum(ll a,ll b,int k) //以a,b开头的k个数之和
{
	if(k == 1) return a;
	if(k == 2) return a + b;
	return (getFib(a, b, k+2) - b + mod) % mod;
}
void PushUp(int rt) {
	sum[rt] = (sum[rt<<1] + sum[rt<<1|1]) % mod;
}

void build(int l,int r,int rt) {
	add1[rt] = 0;
	add2[rt] = 0;
	if (l == r) {
		scanf("%I64d",&sum[rt]);
		return ;
	}
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	PushUp(rt);
}
void add(ll a,ll b,int l,int r,int rt)
{
	sum[rt] = (sum[rt] + getFibsum(a,b,r-l+1)) % mod;
	add1[rt] = (add1[rt] + a) % mod;
	add2[rt] = (add2[rt] + b) % mod;
}
void PushDown(int l,int r,int rt) {
	if(add1[rt] || add2[rt]){
		int m = (l + r) >> 1;
		add(add1[rt],add2[rt],lson);
		add(getFib(add1[rt],add2[rt],m+1-l+1),getFib(add1[rt],add2[rt],m+2-l+1),rson);
		add1[rt] = add2[rt] = 0;
	}
}
void update(int L,int R,int l,int r,int rt) {
	if (L <= l && r <= R) {
		add(fib[l-L+1],fib[l-L+2],l,r,rt);
		return ;
	}
	PushDown(l , r , rt);
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , lson);
	if (m < R) update(L , R, rson);
	PushUp(rt);
}
ll query(int L,int R,int l,int r,int rt) {
	if (L <= l && r <= R) {
		return sum[rt];
	}
	PushDown( l , r , rt);
	int m = (l + r) >> 1;
	ll ret = 0;
	if (L <= m) ret = (ret + query(L , R , lson)) % mod;
	if (m < R) ret = (ret + query(L , R , rson)) % mod;
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
#endif  
	init();
	while(~scanf("%d%d",&n,&m))
	{
		build(1,n,1);
		int ty,L,R;
		while(m--)
		{
			//	cout<<"aaa: "<<query(4,4,1,n,1)<<"bbb: "<<query(5,5,1,n,1)<<endl;
			scanf("%d%d%d",&ty,&L,&R);
			if(ty == 1) update(L,R,1,n,1);
			else
			{
				printf("%I64d\n",query(L,R,1,n,1));
			}
		}
	}
	return 0;
}


引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值