[CF316E3]Summer Homework Solution

題目描述:給你一個序列,實現以下操作:

  • 單點修改:a[i]xa[i]←x
  • 區間查詢i=0rlf[i]×a[i+l]\sum_{i=0}^{r-l}f[i]\times a[i+l],其中f[i]f[i]表示斐波那契第ii項。
  • 區間修改:對於lir,a[i]xl\leq i\leq r,a[i]←x
    首先區間查詢很奇怪,考慮一個東西,任意f[i]f[i]是否可以用x×f[0]+y×f[1]x\times f[0]+y\times f[1]來表示呢?顯然是可以的,而且這個xxyy也是斐波那契裏的一項,還是相鄰的。
    預處理出斐波那契序列及其前綴和。
    考慮線段樹,每個點維護他的長度,以及兩個和:
  • 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[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]……
    那麼考慮怎麼合併兩個點?
    用上面的結論,記當前點爲nownow,左兒子爲leftleft,右兒子爲rightright,有以下式子:
  • now.s[0]=left.s[0]+right.s[0]×f[left.len2]+right.s[1]×f[left.len1]now.s[0]=left.s[0]+right.s[0]\times f[left.len-2]+right.s[1]\times f[left.len-1]
  • now.s[1]=left.s[1]+right.s[0]×f[left.len1]+right.s[1]×f[left.len]now.s[1]=left.s[1]+right.s[0]\times f[left.len-1]+right.s[1]\times 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);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章