对于 \(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;
}