[CF316E3]Summer Homework Solution

题目描述:给你一个序列,实现以下操作:

  • 单点修改: 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=0rlf[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 lir,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.len2]+right.s[1]×f[left.len1]
  • 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.len1]+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);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值