[CF446C]DZY Loves Fibonacci Numbers——线段树+斐波那契数列

版权声明:_ https://blog.csdn.net/lunch__/article/details/82025050

O r z L S T e t e 一下子就给我讲懂了,真的太强了

题目链接

题意大概是维护一个支持区间加区间询问的数据结构,每次加一个斐波那契数列

这个题还是很妙的…让我重新认识了一下斐波那契数列这个神奇的东西

我们先来证明几个小性质

1. f n = ( i = 1 n 2 f i ) + f 2

证明:

f 3 = f 1 + f 2
f 4 = f 3 + f 2 = f 1 + f 2 + f 2
我们发现了 3 <= n <= 4 时候这个性质是满足的
由数学归纳法可知找规律 n > 4
f n = f n 1 + f n 2 = i = 1 n 3 + f 2 + f n 2
f n = ( i = 1 n 2 f i ) + f 2 这个性质得证

得到了这个性质之后 化一下就可以得到 F i b o n a c c i 数列一个快速求和的式子
i = 1 n f i = f n + 2 f 2

2. h n = a 1 f n 1 + a 2 f n 2
h 数列在这里定义为一个类 F i b o n a c c i 数列,即满足 h i = h i 1 + h i 2
但是不满足 f 1 = 1 , f 2 = 1 , 而是 h 1 = a 1 , h 2 = a 2

第一个性质只用到了 F i b o n a c c i 数列 f i = f i 1 + f i 2 这个性质
所以对类 F i b o n a c c i 数列也用着相同的性质

而第二个性质也可以用数学归纳法来证明
h 1 = a 1 , h 2 = a 2
h 3 = h 1 + h 2 = a 1 f 1 + a 2 f 2
h 4 = h 2 + h 3 = a 1 f 2 + a 2 f 3
我们又发现了 3 <= n <= 4 的时候是满足 h n = a 1 f n 2 + a 2 f n 1
n > 4 h n = h n 2 + h n 1 = a 1 f n 4 + a 2 f n 3 + a 1 f n 3 + a 2 f n 4
h n = a 1 ( f n 4 + f n 3 ) + a 2 ( f n 3 + f n 2 ) = a 1 f n 2 + a 2 f n 1
性质 h n = a 1 f n 1 + a 2 f n 2 得证

3.一个类斐波那契数列的一段都加上另一个满足类斐波那契数列的连续一段,那么修改后的这一段还是一个类斐波那契数列。

第三个性质直接带进去就够了,这里就不写证明了

有了这三个性质之后我们就可以来做这个题了

预处理出 F i b o n a c c i 数列的前 n + 2

维护一颗线段树,线段树上信息包括 [ L , R ] 这段类斐波那契数列的第一项和第二项,以及区间和。
我们已经知道了如何通过前两项快速求和的方法和快速求出某一项的方法,那么维护就很简单了,标记下传的时候第一项第二项直接给左区间加上,右区间可以用第二个性质求出前两项再把总和加上去就可以了。

复杂度 O ( n l o g n )

Codes

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

int read() {
    int _ = 0, ___ = 1; char __ = getchar();
    for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = 1;
    for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
    return _ * ___;
}

const int N = 3e5 + 10, mod = 1e9 + 9;
int s[N], f[N];
int n, m;

int ADD(int x, int y) {
    int res = x + y;
    if(res >= mod) res -= mod;
    if(res < 0) res += mod;
    return res;
}

int h(int a1, int a2, int len) {
    if(len == 1) return a1;
    if(len == 2) return a2;
    return ((ll)a1 * f[len - 2] + (ll)a2 * f[len - 1]) % mod;
}

int sum(int a1, int a2, int len) {
    if(len == 1) return a1;
    if(len == 2) return ADD(a1, a2);
    return ADD(h(a1, a2, len + 2), -a2);
}

struct Segment_Tree {
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)

    int a1[N << 2], a2[N << 2], S[N << 2];

    void pushup(int bh) {
        S[bh] = ADD(S[ls], S[rs]);
    }

    void pushdown(int bh, int l, int r) {
        if(a1[bh]) {
            a1[ls] = ADD(a1[ls], a1[bh]), a2[ls] = ADD(a2[ls], a2[bh]);
            S[ls] = ADD(S[ls], sum(a1[bh], a2[bh], mid - l + 1));
            int A1 = h(a1[bh], a2[bh], mid - l + 2), A2 = h(a1[bh], a2[bh], mid - l + 3);
            a1[rs] = ADD(a1[rs], A1), a2[rs] = ADD(a2[rs], A2);
            S[rs] = ADD(S[rs], sum(A1, A2, r - mid));
            a1[bh] = a2[bh] = 0;
        }
     }

    void update(int bh, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            a1[bh] = ADD(a1[bh], f[l - L + 1]);
            a2[bh] = ADD(a2[bh], f[l - L + 2]);
            S[bh] = ADD(S[bh], sum(f[l - L + 1], f[l - L + 2], r - l + 1));
        }
        else {
            pushdown(bh, l, r);
            if(L <= mid) update(ls, l, mid, L, R);
            if(R > mid) update(rs, mid + 1, r, L, R);
            pushup(bh);
        }
    }

    int query(int bh, int l, int r, int L, int R) { 
        int res = 0;
        if(L <= l && r <= R)
            res = S[bh];
        else {
            pushdown(bh, l, r);
            if(L <= mid) res = ADD(res, query(ls, l, mid, L, R));
            if(R > mid) res = ADD(res, query(rs, mid + 1, r, L, R));
        }
        return res;
    }

}T;

void Init() {
    n = read(), m = read();
    for(int i = 1; i <= n; ++ i)
        s[i] = ADD(s[i - 1], read());
    f[1] = f[2] = 1;
    for(int i = 3; i <= n + 2; ++ i)
        f[i] = ADD(f[i - 1], f[i - 2]);
}

int main() {
    freopen("Confidence.in", "r", stdin);
    freopen("Confidence.out", "w", stdout);

    Init();

    int opt, L, R;
    for(int i = 1; i <= m; ++ i) {
        opt = read(), L = read(), R = read();
        if(opt == 1) T.update(1, 1, n, L, R);
        else printf("%d\n", ADD(T.query(1, 1, n, L, R), s[R] - s[L - 1]));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/82025050
今日推荐