【CF316E3】Summer Homework - 线段树
题目描述
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 \(i\geq 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}(i\ge 2)\)
-
给定 \(n\) 个数的序列 \(a\)。\(m\) 次操作。操作有三种:
-
1 x v
:将 \(a_x\) 赋值为 \(v\) -
2 l r
:求 \(\sum_{x=0}^{r-l}(f_x\cdot a_{l+x})\ mod\ 10^9\) -
3 l r d
:将 \(a_l\sim a_r\) 加上 \(d\)
-
-
\(1\le n,m\le 2\times10^5\),\(0\le a_i,v,d\le 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\n",query(1,n,l,r,1).s0);
if (op == 3) {
scanf("%d",&d);
update(1,n,l,r,1,d);
}
}
return 0;
}