文章目录
Description
In mathematical terms, the sequence of Fibonacci numbers is defined by the recurrence relation
DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: . Moreover, there are 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 to each element , where .
- Format of the query "2 l r". In reply to the query you should output the value of modulo .
Help DZY reply to all the queries.
- time limit per test: 4 seconds
- memory limit per test: 256 megabytes
- input: standard input
- output: standard output
Input
The first line of the input contains two integers and . The second line contains integers () — initial array .
Then, lines follow. A single line describes a single query in the format given in the statement. It is guaranteed that for each query inequality 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, .
For the second query, .
After the third query, .
For the fourth query, .
Translation
题意:给出一个数组 ,现在有 个操作,每个操作给出 L 和 R,可能是将这个区间里所有数字加上斐波那契数列对应的项(第 个数字加 ),或者是查询这个区间所有值之和。
Analysis
肯定想到用线段树。但是一般的线段树只能维护加和,需要考虑如何对斐波那契数列也构造 lazy tag。可以发现以下两个结论:
- 如果只存数列的前两项 a 和 b,可以推出这个数列,包括可以 推出第 项和前 项之和。列表可以发现规律:
1 | 2 | 3 | 4 | 5 | ... | n |
---|---|---|---|---|---|---|
a | b | a+b | a+2b | 2a+3b | ... |
( 表示斐波那契数列第 项)
- 如何 求和?
( 表示斐波那契前 项前缀和)
- 这样的数列具有可加性,也就是 lazy tag 如果直接累计不会有问题。
这样我们可以写一个 Fibonacci 相关的模块:
namespace Fibonacci{
int f[maxn],sum[maxn];
inline void build(){
f[1]=f[2]=1;sum[1]=1;sum[2]=2;
for (int i=3;i<=N;i++) f[i]=(f[i-1]+f[i-2])%tt,sum[i]=(sum[i-1]+f[i])%tt;
}
inline int query(int a,int b,int n){
if (n==0) return 0; else
if (n==1) return a%tt; else
if (n==2) return b%tt; else
return (f[n-2]*a%tt+f[n-1]*b%tt)%tt;
}
inline int get_sum(int a,int b,int n){
if (n==0) return 0; else
if (n==1) return a%tt; else
if (n==2) return (a+b)%tt; else
return (a*sum[n-2]%tt+b*sum[n-1]%tt+a%tt)%tt;
}
}
那么接下来我们可以写一个变异的线段树了。打两个烂标记 tag_a 和 tag_b 分别表示数列第一项和第二项。需要注意的是,update 操作时在向下“分割”的时候需要特别注意下数列左端点的两种情况。
建树是不需要的,可以假装原来的序列全是 0,询问的时候再前缀和累加。可以少写一个 build 了~
Code
写这题需要耐心……
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define int long long
const int maxn=300005,N=300000;
const int tt=1000000009;
inline int read(){
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
inline void plus_mod(int &x,int y){
x=(x+y)%tt;
}
namespace Fibonacci{
int f[maxn],sum[maxn];
inline void build(){
f[1]=f[2]=1;sum[1]=1;sum[2]=2;
for (int i=3;i<=N;i++) f[i]=(f[i-1]+f[i-2])%tt,sum[i]=(sum[i-1]+f[i])%tt;
}
inline int query(int a,int b,int n){
if (n==0) return 0; else
if (n==1) return a%tt; else
if (n==2) return b%tt; else
return (f[n-2]*a%tt+f[n-1]*b%tt)%tt;
}
inline int get_sum(int a,int b,int n){
if (n==0) return 0; else
if (n==1) return a%tt; else
if (n==2) return (a+b)%tt; else
return (a*sum[n-2]%tt+b*sum[n-1]%tt+a%tt)%tt;
}
}
#define ls ((p<<1))
#define rs ((p<<1)+1)
#define mid (((tr-tl)>>1)+tl)
namespace SegmentTree{
int sum[maxn*4];
int tag_a[maxn*4],tag_b[maxn*4];
inline void push_down(int tl,int tr,int p){
int as=Fibonacci::query(tag_a[p],tag_b[p],mid+1-tl+1);
int bs=Fibonacci::query(tag_a[p],tag_b[p],mid+2-tl+1);
plus_mod(sum[ls],Fibonacci::get_sum(tag_a[p],tag_b[p],mid-tl+1));
plus_mod(sum[rs],Fibonacci::get_sum(as,bs,tr-(mid+1)+1));
plus_mod(tag_a[ls],tag_a[p]); plus_mod(tag_b[ls],tag_b[p]);
plus_mod(tag_a[rs],as); plus_mod(tag_b[rs],bs);
tag_a[p]=tag_b[p]=0;
}
inline void update(int sl,int sr,int tl,int tr,int p,int a,int b,int st){
if (sl<=tl && tr<=sr){
plus_mod(sum[p],Fibonacci::get_sum(a,b,tr-tl+1));
plus_mod(tag_a[p],a); plus_mod(tag_b[p],b);
return;
}
push_down(tl,tr,p);
int as,bs;
if (sl<=mid ){
update(sl,sr,tl,mid,ls,a,b,st);
as=Fibonacci::query(a,b,mid+1-max(sl,tl)+1);
bs=Fibonacci::query(a,b,mid+2-max(sl,tl)+1);
} else {
as=a;bs=b;
}
if (mid+1<=sr) update(sl,sr,mid+1,tr,rs,as,bs,mid+1);
sum[p]=(sum[ls]+sum[rs])%tt;
}
inline int query(int sl,int sr,int tl,int tr,int p){
if (sl<=tl && tr<=sr) return sum[p];
push_down(tl,tr,p);
int ret=0;
if (sl<=mid ) plus_mod(ret,query(sl,sr,tl,mid,ls));
if (mid+1<=sr) plus_mod(ret,query(sl,sr,mid+1,tr,rs));
return ret%tt;
}
}
int n,m;
int a[maxn],sum[maxn];
signed main(){
Fibonacci::build();
n=read();m=read();
for (int i=1;i<=n;i++) a[i]=read(),sum[i]=(sum[i-1]+a[i])%tt;
for (int i=1;i<=m;i++){
int opt=read(),x=read(),y=read();
if (opt==1){
SegmentTree::update(x,y,1,n,1,1,1,x);
} else if (opt==2){
int ans=SegmentTree::query(x,y,1,n,1);
printf("%lld\n",(ans+sum[y]-sum[x-1]+tt)%tt);
}
}
return 0;
}
颓了半个学期文化课,该回来颓 OI 了 :new_moon_with_face:
我的博客并没有弃坑!