題目描述:給你一個序列,實現以下操作:
- 單點修改:
- 區間查詢,其中表示斐波那契第項。
- 區間修改:對於
首先區間查詢很奇怪,考慮一個東西,任意是否可以用來表示呢?顯然是可以的,而且這個和也是斐波那契裏的一項,還是相鄰的。
預處理出斐波那契序列及其前綴和。
考慮線段樹,每個點維護他的長度,以及兩個和:
那麼考慮怎麼合併兩個點?
用上面的結論,記當前點爲,左兒子爲,右兒子爲,有以下式子:
這個式子便是根據上面那個東西得來的,這個東西十分顯然,隨便算一下就可以直呼簡單。
好了,那麼正解也就呼之欲出了。
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);
}
}
}