对于 \(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; }
来源:https://www.cnblogs.com/Mrzdtz220/p/12318758.html