CF718C Sasha and Array

题面

定义 Fi 为 斐波那契数列的第 i 项的数。你需要实现一个数据结构 a[],支持:

1 l r x:将 [l,r] 的数加上 x

2 l r:求 i=lrFa[i]

1n,m105,1a[i]109

思路

不难看出是线段树,但是怎么计算 Fi 呢?

如果暴力去计算 Fi,显然是不靠谱的(时间复杂度是 O(i))。

如果使用斐波那契末项计算公式(参见 P1720 月落乌啼算钱(斐波那契数列))也不靠谱,不容易维护。

如果做过 P1962 斐波那契数列 的同学可能知道,可以用矩阵快速幂计算。

大致公式如下:

[1110]i=Fi

OI-Wiki 上有证明。

然后就是维护一个区间修改区间查询线段树。时间复杂度是 O(nlog2n)

代码

代码里面有封装好了的矩阵模板,供大家随意使用。

#include <bits/stdc++.h>
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
#define int long long
using namespace std;

const int MOD = 1e9+7;

struct Matrix{
	int a[3][3];
	const int size = 2;
	Matrix(){
		memset(a,0,sizeof(a));
	}
	Matrix(int aba){
		a[aba][aba]=1;
		a[aba][aba+1]=0;
		a[aba+1][aba]=0;
		a[aba+1][aba+1]=1;
	}
	Matrix(int A,int b,int c,int d){
		a[1][1]=A;
		a[1][2]=b;
		a[2][1]=c;
		a[2][2]=d;
	}
	Matrix operator*(const Matrix &ano) const {
		Matrix ans;
		for(int i=1;i<=size;i++){
			for(int k=1;k<=size;k++){
				for(int j=1;j<=size;j++){
					ans.a[i][k]=(ans.a[i][k]+a[i][j]*ano.a[j][k])%MOD;
				}
			}
		}
		return ans;
	}	
	Matrix operator+(const Matrix aa){
		Matrix res;
		for(int i=1;i<=size;i++){
			for(int j=1;j<=size;j++){
				res.a[i][j]=a[i][j]+aa.a[i][j];
				res.a[i][j]%=MOD;
			}
		}
		return res;
	}
	void operator=(const Matrix A){
		for(int i=1;i<=size;i++){
			for(int j=1;j<=size;j++){
				a[i][j]=A.a[i][j];
			}
		}
	}
	bool empty(){
		return (a[1][1]==0)&&(a[1][2]==0)&&(a[2][1]==0)&&(a[2][2]==0);
	}
	Matrix operator^(int power){
		Matrix res(1);
		Matrix base = (*this);
		while(power){
			if(power&1){
				res=res*base;
			}
			base=base*base;
			power>>=1;
		}
		return res;
	}
};



const int SIZE = 1e5+5;
Matrix t[SIZE<<2],tag[SIZE<<2];
int v[SIZE];
const Matrix unit(1);
int n,m;

inline void pushup(int i){
	t[i]=t[ls]+t[rs];
}

void build(int i,int l,int r){
	tag[i]=unit;
	if(l==r){
		t[i]=Matrix(1,1,0,0)*(Matrix(1,1,1,0)^(v[l]-1));
		return;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(i);
}

void pushdown(int i){
	if(tag[i].empty()){
		return;
	}
	t[ls]=t[ls]*tag[i];
	tag[ls]=tag[ls]*tag[i];
	t[rs]=t[rs]*tag[i];
	tag[rs]=tag[rs]*tag[i];
	tag[i]=unit;
}

void update(int i,int ql,int qr,int l,int r,Matrix x){
	if(ql<=l && qr>=r){
		t[i]=t[i]*x;
		tag[i]=tag[i]*x;
		return;
	}
	pushdown(i);
	if(ql<=mid){
		update(ls,ql,qr,l,mid,x);
	}
	if(qr>mid){
		update(rs,ql,qr,mid+1,r,x);
	}
	pushup(i);
}

Matrix query(int i,int ql,int qr,int l,int r){
	if(ql<=l && qr>=r){
		return t[i];
	}
	pushdown(i);
	Matrix res;
	if(ql<=mid){
		res = res + query(ls,ql,qr,l,mid);
	}
	if(qr > mid){
		res = res+query(rs,ql,qr,mid+1,r);
	}
	return res;
}

signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	build(1,1,n);
	while(m--){
		int op,l,r,x;
		cin>>op;
		if(op==1){
			cin>>l>>r>>x;
			update(1,l,r,1,n,Matrix(1,1,1,0)^x);
		}
		else{
			cin>>l>>r;
			cout<<(query(1,l,r,1,n).a[1][2]%MOD)<<'\n';
		}
	}
	return 0;
}

posted @   蒟蒻xiezheyuan  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示