题目描述
By the age of three Smart Beaver mastered all arithmetic operations and got this summer homework from the amazed teacher:
You are given a sequence of integers (a_{1},a_{2},...,a_{n}). Your task is to perform on it mm consecutive operations of the following type:
-
For given numbers (x_{i}) and (v_{i}) assign value (v_{i}) to element (a_{x_i}).
-
For given numbers (l_{i}) and (r_{i}) you've got to calculate sum (Sigma_{x=0}^{r_i-l_i}f_xa_{l_i+x}), where (f_{0}=f_{1}=1) and at (igeq 2) : (f_{i}=f_{i-1}+f_{i-2}).
-
For a group of three numbers (l_{i}) (r_{i}) (d_{i}) you should increase value (a_{x}) by (d_{i}) for all (x) ((l_{i}<=x<=r_{i}))).
Smart Beaver planned a tour around great Canadian lakes, so he asked you to help him solve the given problem.
题目大意
-
在这里,我们用 (f_i) 表示第 (i) 个斐波那契数 (f_0=1,f_1=1,f_i=f_{i-1}+f_{i-2}(ige 2))
-
给定 (n) 个数的序列 (a)。(m) 次操作。操作有三种:
-
1 x v
:将 (a_x) 赋值为 (v) -
2 l r
:求 (sum_{x=0}^{r-l}(f_xcdot a_{l+x}) mod 10^9) -
3 l r d
:将 (a_lsim a_r) 加上 (d)
-
-
(1le n,mle 2 imes10^5),(0le a_i,v,dle 10^5)
思路
对于一个区间 ([l,r]),用线段树维护一个 (s_n),其中 (s_n=Sigma_{i=0}^{r-l}a_{l+i}f_{i+n}),即 ({f}) 从第 (n) 项开始与 ({a}) 对应相乘求和
那么题中所求就是 (s_0),对于一个区间 seg
,它的左右儿子是 lson
和 rson
,那么有 (seg.s_n = lson.s_n+rson.s_{n+lson.len})
同时,({s}) 与 ({f}) 有相同的递推性质,即 (s_n=s_{n-1}+s_{n-2}),因为:
(s_{n-1}+s_{n-2}=Sigma_{i=0}^{r-l}a_{l+i}f_{i+n-1}+Sigma_{i=0}^{r-l}a_{l+i}f_{i+n-2}=Sigma_{i=0}^{r-l}a_{l+i}(f_{i+n-1}+f_{i+n-2})=Sigma_{i=0}^{r-l}a_{l+i}f_{i+n}=s_n)
那么只用线段树记录下 (s_0,s_1) ,就可递推出 (s_n)
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 2e5 + 10;
const int mod = 1e9;
int n,m,f[maxn] = { 1,1 },pre[maxn] = { 1,2 },laz[maxn<<2];
struct func {
int s0,s1;
inline int s(int x) {
if (x == 0) return s0;
if (x == 1) return s1;
return (1ll*f[x-2]*s0%mod+1ll*f[x-1]*s1%mod)%mod;
}
} t[maxn<<2];
inline void pushup(int root,int l,int r) {
int mid = l+r>>1;
t[root].s0 = (t[root<<1].s0+t[root<<1|1].s(mid-l+1))%mod;
t[root].s1 = (t[root<<1].s1+t[root<<1|1].s(mid-l+2))%mod;
}
inline void pushdown(int root,int l,int r) {
int mid = l+r>>1;
if (laz[root]) {
(laz[root<<1] += laz[root])%= mod;
(laz[root<<1|1] += laz[root])%= mod;
(t[root<<1].s0 += 1ll*laz[root]*pre[mid-l]%mod) %= mod;
(t[root<<1|1].s0 += 1ll*laz[root]*pre[r-mid-1]%mod) %= mod;
(t[root<<1].s1 += 1ll*laz[root]*(pre[mid-l+1]-pre[0])%mod) %= mod;
(t[root<<1|1].s1 += 1ll*laz[root]*(pre[r-mid]-pre[0])%mod) %= mod;
laz[root] = 0;
}
}
inline void build(int l,int r,int root) {
if (l == r) {
scanf("%d",&t[root].s0);
t[root].s1 = t[root].s0;
return;
}
int mid = l+r>>1;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
pushup(root,l,r);
}
inline void update(int l,int r,int ul,int ur,int root,int x) {
if (l > ur || r < ul) return;
if (ul <= l && r <= ur) {
laz[root] += x;
(t[root].s0 += 1ll*x*pre[r-l]%mod) %= mod;
(t[root].s1 += 1ll*x*(pre[r-l+1]-pre[0])%mod) %= mod;
return;
}
pushdown(root,l,r);
int mid = l+r>>1;
update(l,mid,ul,ur,root<<1,x);
update(mid+1,r,ul,ur,root<<1|1,x);
pushup(root,l,r);
}
inline func query(int l,int r,int ql,int qr,int root) {
if (ql <= l && r <= qr) return t[root];
pushdown(root,l,r);
int mid = l+r>>1;
if (mid < ql) return query(mid+1,r,ql,qr,root<<1|1);
else if (mid >= qr) return query(l,mid,ql,qr,root<<1);
else {
func ls = query(l,mid,ql,qr,root<<1),rs = query(mid+1,r,ql,qr,root<<1|1);
return (func){ (ls.s0+rs.s(mid-max(l,ql)+1))%mod,(ls.s1+rs.s(mid-max(l,ql)+2))%mod };
}
}
int main() {
scanf("%d%d",&n,&m);
for (int i = 2;i <= n;i++) {
f[i] = (f[i-1]+f[i-2])%mod;
pre[i] = (pre[i-1]+f[i])%mod;
}
for (build(1,n,1);m--;) {
int op,l,r,d;
scanf("%d%d%d",&op,&l,&r);
if (op == 1) update(1,n,l,l,1,r-query(1,n,l,l,1).s0);
if (op == 2) printf("%d
",query(1,n,l,r,1).s0);
if (op == 3) {
scanf("%d",&d);
update(1,n,l,r,1,d);
}
}
return 0;
}