ABBYY Cup 3.0 E3. Summer Homework

懵懂的女人 提交于 2020-02-16 21:56:10

对于 \(f_0=f_1=1\) 的斐波那契数列有一个性质 \[f_i=f_{i-k}*f_k+f_{i-k-1}*f_{k-1}, \forall k \in \left[1, i\right)\]
数学归纳法证一下
\(k=1\) 时,\(f_i=f_{i-1}*f_1+f_{i-2}*f_0=f_{i-1}+f_{i-2}\)
\(k'=k\) 成立, 当 \(k'=k+1\) 时,\[\begin{aligned}f_i= &f_{i-k-1}*f_{k+1}+f_{i-k-2}*f_k \\= & f_{i-k-1}*(f_k+f_{k-1})+f_{i-k-2}*f_k \\=& f_{i-k-1}*f_{k-1}+f_{i-k-1}*f_k+f_{i-k-2}*f_k \\=&f_{i-k-1}*f_{k-1}+f_{i-k}*f_k \end{aligned}\]
对线段树每个节点维护区间长度 \(len\)\(s_0= \sum\limits_{i=0}^{len-1}f_i * a_i\)\(s_1=\sum\limits_{i=0}^{len-1}f_{i+1}*a_i\)
合并两个区间时 \[s_0=s_{lson, 0}+s_{rson, 0}*f_{len_{lson}-2}+s_{rson, 1}*f_{len_{lson}-1}\]
\[s_1=s_{lson, 1}+s_{rson, 0}*f_{len_{lson}-1}+s_{rson, 1}*f_{len_{lson}}\]
区间修改对一个区间的影响为 \[s_0 = s_0 + v * \sum_{i=0}^{len-1}f_i\]
\[s_1=s_1+v*\sum_{i=1}^{len}f_i\]

#include <bits/stdc++.h>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)

namespace IO {
    char buf[1 << 21], *p1 = buf, *p2 = buf;
    inline void read() {}
    inline int getc() {
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
    }
    template <typename T, typename... T2>
    inline void read(T &x, T2 &... oth) {
        T f = 1; x = 0;
        char ch = getc();
        while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getc(); }
        while (isdigit(ch)) { x = x * 10 + ch - 48; ch = getc(); }
        x *= f;
        read(oth...);
    }
}

const int N = 2e5 + 7, MOD = 1e9;
inline void M(int &x) {
    if (x >= MOD) x -= MOD;
    if (x < 0) x += MOD;
}

int a[N], f[N], s[N], n, m;
int tag[N * 4];
struct Node {
    int s0, s1, len;
    inline void read() {
        IO::read(s0); s1 = s0; len = 1;
    }
    inline Node operator + (const Node &p) const {
        Node all;
        all.len = len + p.len;
        M(all.s0 = s0 + (1LL * p.s0 * f[len - 2] % MOD + 1LL * p.s1 * f[len - 1] % MOD) % MOD);
        M(all.s1 = s1 + (1LL * p.s0 * f[len - 1] % MOD + 1LL * p.s1 * f[len] % MOD) % MOD);
        return all;
    }
    inline void set(int v) {
        s0 = s1 = v;
        len = 1;
    }   
} tree[N * 4];

inline void done(int p, int v) {
    M(tree[p].s0 += 1LL * s[tree[p].len - 1] * v % MOD);
    M(tree[p].s1 += 1LL * s[tree[p].len] * v % MOD);
    M(tree[p].s1 -= v);
    M(tag[p] += v);
}

inline void pushdown(int p) {
    if (!tag[p]) return;
    done(lp, tag[p]); done(rp, tag[p]);
    tag[p] = 0;
}

void build(int p, int l, int r) {
    if (l == r)  return tree[p].read();
    build(lp, l, mid); build(rp, mid + 1, r);
    tree[p] = tree[lp] + tree[rp];
}

void update(int p, int l, int r, int pos, int v) {
    if (l == r) return tree[p].set(v);
    pushdown(p);
    if (pos <= mid) update(lp, l, mid, pos, v);
    else update(rp, mid + 1, r, pos, v);
    tree[p] = tree[lp] + tree[rp];
}

void update(int p, int l, int r, int x, int y, int v) {
    if (x <= l && y >= r) return done(p, v);
    pushdown(p);
    if (x <= mid) update(lp, l, mid, x, y, v);
    if (y > mid) update(rp, mid + 1, r, x, y, v);
    tree[p] = tree[lp] + tree[rp];
}

Node query(int p, int l, int r, int x, int y) {
    if (x <= l && y >= r) return tree[p];
    pushdown(p);
    if (y <= mid) return query(lp, l, mid, x, y);
    if (x > mid) return query(rp, mid + 1, r, x, y);
    return query(lp, l, mid, x, y) + query(rp, mid + 1, r, x, y);
}

int main() {
    IO::read(n, m);
    f[0] = f[1] = s[0] = 1; s[1] = 2;
    for (int i = 2; i <= n; i++)
        M(f[i] = f[i - 1] + f[i - 2]), M(s[i] = f[i] + s[i - 1]);
    build(1, 1, n);
    for (int opt, l, r, v; m--; ) {
        IO::read(opt, l, r);
        if (opt == 1) {
            update(1, 1, n, l, r);
        } else if (opt == 2) {
            printf("%d\n", query(1, 1, n, l, r).s0);
        } else {
            IO::read(v);
            update(1, 1, n, l, r, v);
        } 
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!