C. DZY Loves Fibonacci Numbers(线段树&fibonacci)

考虑 f i b o n a c c i fibonacci fibonacci的几个性质:


  • 两个的广义斐波那契数列和仍是广义斐波那契数列。
  • 对于广义斐波那契数列: g [ a , b ] g[a,b] g[a,b], ( a , b ) (a,b) (a,b)分别是第一项和第二项。有

    • g n = f n − 2 × a + f n − 1 × b g_n=f_{n-2}\times a+f_{n-1} \times b gn=fn−2×a+fn−1×b
    • ∑ i = 1 n g i = g n + 2 − g 2 \sum\limits_{i=1}^n g_i=g_{n+2}-g_2 i=1∑ngi=gn+2−g2


因此,每次区间加 [ l , r ] [l,r] [l,r]操作,我们可以用线段树维护每段区间的 g 1 , g 2 , s u m g_1,g_2,sum g1,g2,sum 分别是这段区间的广义 f i b fib fib第一项和第二项,与区间和。

对于合并子树操作就是:

a [ r t ] . s = a [ l s o n ] . s + a [ r s o n ] . s + ∑ i = l r g i a[rt].s=a[lson].s+a[rson].s+\sum\limits_{i=l}^r g_i a[rt].s=a[lson].s+a[rson].s+i=l∑rgi

令 l e n = r − l + 1 len=r-l+1 len=r−l+1

而 ∑ i = l r = g l e n + 2 − g 2 = f [ l e n ] × g 1 + f [ l e n + 1 ] × g 2 \sum\limits_{i=l}^r=g_{len+2}-g_{2}=f[len]\times g_1+f[len+1]\times g_2 i=l∑r=glen+2−g2=f[len]×g1+f[len+1]×g2

所以可以 O ( 1 ) O(1) O(1) 合并。

至于下传影响:

左子树的 g 1 , g 2 g_1,g_2 g1,g2显然直接根据性质1直接加。

右子树类似地,加上对应的 g m i d + 1 , g m i d + 2 g_{mid+1},g_{mid+2} gmid+1,gmid+2 m i d + 1 mid+1 mid+1也就是右子树的 L L L左端点。

而 g m i d + 1 = f m i d − 1 × g 1 + f m i d × g 2 ) g_{mid+1}=f_{mid-1}\times g_1+f_{mid}\times g_2) gmid+1=fmid−1×g1+fmid×g2)

g m i d + 1 g_{mid+1} gmid+1 同理。

il void pd(int x){
if(a[x].f1||a[x].f2){
a[lx].f1+=a[x].f1,a[lx].f2+=a[x].f2;
//加上 a[mid+1].val
a[rx].f1+=a[x].f1*f[len(lx)-1]+a[x].f2*f[len(lx)];
//加上 a[mid+2].val
a[rx].f2+=a[x].f1*f[len(lx)]+a[x].f2*f[len(lx)+1];
re(lx),re(rx);
a[x].f1=a[x].f2=0;
}
}

时间复杂度: O ( m l o g n ) O(mlogn) O(mlogn)

// Problem: C. DZY Loves Fibonacci Numbers
// Contest: Codeforces - Codeforces Round #FF (Div. 1)
// URL: https://codeforces.com/problemset/problem/446/C
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// Date: 2021-11-27 17:04:10
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=3e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+9;
const int hashmod[4] = {402653189,805306457,1610612741,998244353};
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
template <typename T> //x=max(x,y) x=min(x,y)
void cmx(T &x,T y){
if(x<y) x=y;
}
template <typename T>
void cmn(T &x,T y){
if(x>y) x=y;
}
int n,m;
ll f[N];
void init(){
f[1]=f[2]=1;
rep(i,3,n+1) f[i]=(f[i-1]+f[i-2])%mod;
}
//区间修改 区间求和
#define il inline
#define lx x<<1
#define rx x<<1|1
#define len(x) (a[x].r-a[x].l+1)
struct SegTree{
struct node{
int l,r;
ll f1,f2;
ll s;
}a[N<<4];
il void re(int x){
a[x].f1%=mod,a[x].f2%=mod;
a[x].s=a[lx].s+a[rx].s+(a[x].f1*f[len(x)]+a[x].f2*f[len(x)+1])-a[x].f2;
a[x].s%=mod;
}
il void pd(int x){
if(a[x].f1||a[x].f2){
a[lx].f1+=a[x].f1,a[lx].f2+=a[x].f2;
//加上 a[mid+1].val
a[rx].f1+=a[x].f1*f[len(lx)-1]+a[x].f2*f[len(lx)];
//加上 a[mid+2].val
a[rx].f2+=a[x].f1*f[len(lx)]+a[x].f2*f[len(lx)+1];
re(lx),re(rx);
a[x].f1=a[x].f2=0;
}
}
il void bud(int x,int l,int r){
a[x].l=l,a[x].r=r;
if(l==r){
return;
}
int m=(l+r)>>1;bud(lx,l,m),bud(rx,m+1,r);
//re(x);
}
il void upd(int x,int l,int r){
if(a[x].l>=l&&a[x].r<=r){
a[x].f1+=f[a[x].l-l+1];
a[x].f2+=f[a[x].l-l+2];
re(x);return;
}
pd(x);
int m=(a[x].l+a[x].r)>>1;
if(l<=m) upd(lx,l,r);
if(r>m) upd(rx,l,r);
re(x);
}
il ll que(int x,int l,int r){
if(a[x].l>=l&&a[x].r<=r) return a[x].s;
pd(x);
int m=(a[x].l+a[x].r)>>1;ll ans=0;
if(l<=m) (ans+=que(lx,l,r))%=mod;
if(r>m) (ans+=que(rx,l,r))%=mod;
return ans;
}
}T;
ll a[N];
int main(){
scanf("%d%d",&n,&m);init();T.bud(1,1,n);
rep(i,1,n) scanf("%lld",&a[i]),a[i]+=a[i-1];
while(m--){
int op,l,r;scanf("%d%d%d",&op,&l,&r);
if(op==1) T.upd(1,l,r);
else printf("%lld\n",(T.que(1,l,r)+a[r]-a[l-1]+mod)%mod);
}
return 0;
}