题目描述:给你一个序列,实现以下操作:
- 单点修改: a [ i ] ← x a[i]←x a[i]←x
- 区间查询 ∑ i = 0 r − l f [ i ] × a [ i + l ] \sum_{i=0}^{r-l}f[i]\times a[i+l] ∑i=0r−lf[i]×a[i+l],其中 f [ i ] f[i] f[i]表示斐波那契第 i i i项。
- 区间修改:对于
l
≤
i
≤
r
,
a
[
i
]
←
x
l\leq i\leq r,a[i]←x
l≤i≤r,a[i]←x
首先区间查询很奇怪,考虑一个东西,任意 f [ i ] f[i] f[i]是否可以用 x × f [ 0 ] + y × f [ 1 ] x\times f[0]+y\times f[1] x×f[0]+y×f[1]来表示呢?显然是可以的,而且这个 x x x和 y y y也是斐波那契里的一项,还是相邻的。
预处理出斐波那契序列及其前缀和。
考虑线段树,每个点维护他的长度,以及两个和: - s [ 0 ] = f [ 0 ] × a [ l ] + f [ 1 ] × a [ l + 1 ] + f [ 2 ] × a [ l + 2 ] … … s[0]=f[0]\times a[l]+f[1]\times a[l+1]+f[2]\times a[l+2]…… s[0]=f[0]×a[l]+f[1]×a[l+1]+f[2]×a[l+2]……
-
s
[
1
]
=
f
[
1
]
×
a
[
l
]
+
f
[
2
]
×
a
[
l
+
1
]
+
f
[
3
]
×
a
[
l
+
2
]
…
…
s[1]=f[1]\times a[l]+f[2]\times a[l+1]+f[3]\times a[l+2]……
s[1]=f[1]×a[l]+f[2]×a[l+1]+f[3]×a[l+2]……
那么考虑怎么合并两个点?
用上面的结论,记当前点为 n o w now now,左儿子为 l e f t left left,右儿子为 r i g h t right right,有以下式子: - n o w . s [ 0 ] = l e f t . s [ 0 ] + r i g h t . s [ 0 ] × f [ l e f t . l e n − 2 ] + r i g h t . s [ 1 ] × f [ l e f t . l e n − 1 ] now.s[0]=left.s[0]+right.s[0]\times f[left.len-2]+right.s[1]\times f[left.len-1] now.s[0]=left.s[0]+right.s[0]×f[left.len−2]+right.s[1]×f[left.len−1]
-
n
o
w
.
s
[
1
]
=
l
e
f
t
.
s
[
1
]
+
r
i
g
h
t
.
s
[
0
]
×
f
[
l
e
f
t
.
l
e
n
−
1
]
+
r
i
g
h
t
.
s
[
1
]
×
f
[
l
e
f
t
.
l
e
n
]
now.s[1]=left.s[1]+right.s[0]\times f[left.len-1]+right.s[1]\times f[left.len]
now.s[1]=left.s[1]+right.s[0]×f[left.len−1]+right.s[1]×f[left.len]
这个式子便是根据上面那个东西得来的,这个东西十分显然,随便算一下就可以直呼简单。
好了,那么正解也就呼之欲出了。
code:
#include <bits/stdc++.h>
#define regi register int
#define mod 1000000000
int n,m;
int f[1000001],s[1000001],a[1000001];
struct smt{
int s[2];
int len;
int lazy;
}t[2000001];
inline int read(){
int r=0,w=0,c;
for(;!isdigit(c=getchar());r=c);
for(w=c^48;isdigit(c=getchar());w=w*10+(c^48));
return r^45?w:-w;
}
inline int add(int x,int y){
return 1LL*(x+y)>mod?x+y-mod:x+y;
}
inline int addself(int &x,int y){
x=add(x,y);
}
inline int dec(int x,int y){
return 1LL*(x-y)<0?x-y+mod:x-y;
}
inline int decself(int &x,int y){
return x=dec(x,y);
}
inline int mul(int x,int y){
return 1LL*x*y%mod;
}
inline int mulself(int &x,int y){
return x=mul(x,y);
}
inline void Prework(){
f[0]=1,f[1]=1;
s[0]=1,s[1]=2;
for(regi i=2;i<=999999;++i)
f[i]=add(f[i-1],f[i-2]),
s[i]=add(s[i-1],f[i]);
}
inline int F(int x){
return x<0?0:f[x];
}
inline void UP(smt &me,smt l,smt r){
me.len=l.len+r.len;
me.s[0]=add(l.s[0],add(mul(r.s[0],F(l.len-2)),mul(r.s[1],F(l.len-1))));
me.s[1]=add(l.s[1],add(mul(r.s[0],F(l.len-1)),mul(r.s[1],F(l.len))));
}
inline int ls(int now){
return now<<1;
}
inline int rs(int now){
return now<<1|1;
}
inline void update(int now,int l,int r,int val){
int len=r-l+1;
addself(t[now].s[0],mul(val,s[len-1]));
addself(t[now].s[1],dec(mul(val,s[len]),val));
}
inline void pushdown(int now,int l,int r){
addself(t[ls(now)].lazy,t[now].lazy);
addself(t[rs(now)].lazy,t[now].lazy);
update(ls(now),l,l+r>>1,t[now].lazy);
update(rs(now),(l+r>>1)+1,r,t[now].lazy);
t[now].lazy=0;
}
void btt(int now,int l,int r){
if(l==r){
t[now].len=1;
t[now].s[0]=t[now].s[1]=a[l];
return;
}
int mid=l+r>>1;
btt(ls(now),l,mid);
btt(rs(now),mid+1,r);
UP(t[now],t[ls(now)],t[rs(now)]);
}
void change(int now,int l,int r,int x,int val){
if(l==r){
t[now].s[0]=t[now].s[1]=val;
return;
}
pushdown(now,l,r);
int mid=l+r>>1;
if(x>mid)
change(rs(now),mid+1,r,x,val);
else
change(ls(now),l,mid,x,val);
UP(t[now],t[ls(now)],t[rs(now)]);
}
void GX(int now,int l,int r,int L,int R,int val){
if(R<l||L>r)
return;
if(L<=l&&r<=R){
addself(t[now].lazy,val);
update(now,l,r,val);
return;
}
pushdown(now,l,r);
int mid=l+r>>1;
GX(ls(now),l,mid,L,R,val);
GX(rs(now),mid+1,r,L,R,val);
UP(t[now],t[ls(now)],t[rs(now)]);
}
smt ask(int now,int l,int r,int L,int R){
if(l==L&&r==R)
return t[now];
pushdown(now,l,r);
int mid=l+r>>1;
if(R<=mid)
return ask(ls(now),l,mid,L,R);
if(L>mid)
return ask(rs(now),mid+1,r,L,R);
smt shift;
UP(shift,ask(ls(now),l,mid,L,mid),ask(rs(now),mid+1,r,mid+1,R));
return shift;
}
main(){
Prework();
n=read(),m=read();std::generate(a+1,a+n+1,read);
btt(1,1,n);
for(regi i=1,op,x,y;i<=m;++i){
op=read(),x=read(),y=read();
if(op==1)
change(1,1,n,x,y);
if(op==2)
printf("%d\n",ask(1,1,n,x,y).s[0]);
if(op==3){
regi z=read();
GX(1,1,n,x,y,z);
}
}
}