CodeForces - 316E3 Summer Homework

Discription

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 a1, a2, ..., an. Your task is to perform on it mconsecutive operations of the following type:

  1. For given numbers xi and vi assign value vi to element axi.
  2. For given numbers li and ri you've got to calculate sum , where f0 = f1 = 1 and at i ≥ 2: fi = fi - 1 + fi - 2.
  3. For a group of three numbers li ri di you should increase value ax by di for allx (li ≤ x ≤ ri).

Smart Beaver planned a tour around great Canadian lakes, so he asked you to help him solve the given problem.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 2·105) — the number of integers in the sequence and the number of operations, correspondingly. The second line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 105). Then follow m lines, each describes an operation. Each line starts with an integer ti (1 ≤ ti ≤ 3) — the operation type:

  • if ti = 1, then next follow two integers xi vi (1 ≤ xi ≤ n, 0 ≤ vi ≤ 105);
  • if ti = 2, then next follow two integers li ri (1 ≤ li ≤ ri ≤ n);
  • if ti = 3, then next follow three integers li ri di (1 ≤ li ≤ ri ≤ n, 0 ≤ di ≤ 105).

The input limits for scoring 30 points are (subproblem E1):

  • It is guaranteed that n does not exceed 100, m does not exceed 10000 and there will be no queries of the 3-rd type.

The input limits for scoring 70 points are (subproblems E1+E2):

  • It is guaranteed that there will be queries of the 1-st and 2-nd type only.

The input limits for scoring 100 points are (subproblems E1+E2+E3):

  • No extra limitations.

Output

For each query print the calculated sum modulo 1000000000 (109).

Examples

Input
5 5
1 3 1 2 4
2 1 4
2 1 5
2 2 4
1 3 10
2 1 5
Output
12
32
8
50
Input
5 4
1 3 1 2 4
3 1 4 1
2 2 4
1 2 10
2 1 5
Output
12
45


最近好多 数学 + 数据结构 的题啊qwq,既要动脑子又要调代码qwq
斐波那契数列有一个非常好的性质: f[i] = f[i-1] + f[i-2]
这不是废话吗。。。。但是这个能推出来另一个东西 -> f[i] = f[k]*f[i-k] + f[k-1]*f[i-k-1] (这个式子是对于f[0]=f[1]=1的斐波那契数列而言的)。
有了这个,我们就可以随心所欲的通过 ∑f[i]*a[i+l] 和 ∑f[i+1]*a[i+l] 来构造任意 ∑f[i+d]*a[i+l] 啦(也就是程序中的Get函数)。

然后随便打打标机(别忘了下传维护之类的),随便合并合并子树,就可以A啦(但是要写一坨子qwq)
(最近压行成瘾qwq)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2*1e5,ha=1e9;
int f[maxn+5],F[maxn+5],a[maxn+5],le,ri,n,m,w,O;
int sum[maxn*4+5][2],tag[maxn*4+5],L[maxn*4+5],A;
inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
inline void init(){ f[0]=F[0]=1; for(int i=1;i<=maxn;i++) f[i]=add(f[i-1],f[i-2]),F[i]=add(f[i],F[i-1]);}
inline int Get(int o,int Derta){ return Derta<2?(Derta?sum[o][1]:sum[o][0]):add(sum[o][0]*(ll)f[Derta-2]%ha,sum[o][1]*(ll)f[Derta-1]%ha);}
inline void QADD(int o,int Derta){ ADD(tag[o],Derta),ADD(sum[o][0],Derta*(ll)F[L[o]-1]%ha),ADD(sum[o][1],Derta*(ll)add(F[L[o]],ha-1)%ha);}
inline void pushdown(int o,int lc,int rc){ if(tag[o]){ QADD(lc,tag[o]),QADD(rc,tag[o]),tag[o]=0;}}
inline void Merge(int o,int lc,int rc,int Derta){
	sum[o][0]=add(sum[lc][0],Get(rc,Derta));
	sum[o][1]=add(sum[lc][1],Get(rc,Derta+1));
}

void build(int o,int l,int r){
	L[o]=r-l+1;
	if(l==r){ sum[o][0]=sum[o][1]=a[l]; return;}
	int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	Merge(o,lc,rc,mid+1-l);
}

void update1(int o,int l,int r){
	if(l==r){ sum[o][0]=sum[o][1]=w; return;}
	int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
	pushdown(o,lc,rc);
	if(le<=mid) update1(lc,l,mid);
	else update1(rc,mid+1,r);
	Merge(o,lc,rc,mid+1-l);
}

void update2(int o,int l,int r){
	if(l>=le&&r<=ri){ QADD(o,w); return;}
	int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
	pushdown(o,lc,rc);
	if(le<=mid) update2(lc,l,mid);
	if(ri>mid) update2(rc,mid+1,r);
	Merge(o,lc,rc,mid+1-l);	
}

void query(int o,int l,int r){
	if(l>=le&&r<=ri){ ADD(A,Get(o,l-le)); return;}
	int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
	pushdown(o,lc,rc);
	if(le<=mid) query(lc,l,mid);
	if(ri>mid) query(rc,mid+1,r);
}

inline void solve(){
	while(m--){
		scanf("%d",&O);
		if(O==1){ scanf("%d%d",&le,&w),update1(1,1,n);}
		else if(O==2){ scanf("%d%d",&le,&ri),A=0,query(1,1,n),printf("%d\n",A);}
		else{ scanf("%d%d%d",&le,&ri,&w),update2(1,1,n);}
	}
}

int main(){
	init();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",a+i);
	build(1,1,n);
	solve();
	return 0;
}

  

 

转载于:https://www.cnblogs.com/JYYHH/p/8982220.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值