ABBYY Cup 3.0 E3. Summer Homework

对于 \(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;
}
posted @ 2020-02-16 21:11  Mrzdtz220  阅读(101)  评论(0)    收藏  举报