CF 718C 综合练习6

题目翻译:

有一个长为 \(n\) 的数列 \(a_{1},a_{2}...a_{n}\) ,你需要对这个数列维护如下两种操作:

  1. \(1\space l \space r\space x\) 表示将数列中的 \(a_{l},a_{l+1}...a_{r-1},a_{r}\) 加上 \(x\)
  2. \(2\space l\space r\) 表示要你求出 \(\sum_{i=l}^{r}fib(a_{i})\) 对 \(10^9+7\) 取模后的结果

\(fib(x)\) 表示的是斐波那契的第 \(x\) 项, \(fib(1)=1,fib(2)=1,fib(i)=fib(i-1)+fib(i-2)(i>2)\)


显然的线段树维护

我们知道斐波那契数列的某一项可以表示成

\(A\times B^n\) 的形式,\(A,B\) 都是矩阵

那么 \(A\times B^n + A\times C^m=A\times (B^n+C^m)\)

所以就是一个区间乘法修改+区间加法和查询来维护矩阵

// This code writed by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define int long long
using namespace std;
const int MaxN=100050;
const int p=1e9+7;
struct Mat
{
	int a[2][2];
	inline void clear()
	{
		memset(a,0,sizeof a);
		return;
	}
	inline Mat operator + (const Mat &nt)
	{
		Mat ans;ans.clear();
		for(int i=0;i<2;++i)
			for(int j=0;j<2;++j)
				ans.a[i][j]=(a[i][j]+nt.a[i][j])%p;
		return ans;
	}
	inline Mat operator += (const Mat &nt)
	{
		return *this=*this+nt;
	}
	inline Mat operator * (const Mat &nt)
	{
		Mat ans;ans.clear();
		for(int i=0;i<2;++i)
			for(int j=0;j<2;++j)
				for(int k=0;k<2;++k)
					ans.a[i][j]=(ans.a[i][j]+a[i][k]*nt.a[k][j]%p)%p;
		return ans;
	}
	inline Mat operator *= (const Mat &nt)
	{
		return *this=*this*nt;
	}
	inline bool operator != (const Mat &nt) const
	{
		return a[0][0]!=nt.a[0][0]||a[0][1]!=nt.a[0][1]||
				a[1][0]!=nt.a[1][0]||a[1][1]!=nt.a[1][1];
	}
}matoption;
Mat val[MaxN<<2],lazy[MaxN<<2];
int a[MaxN];
Mat One={1,0,0,0};
Mat base={1,1,1,0};
Mat Zero={1,0,0,1};
inline Mat fib(Mat a,int b)
{
	reg Mat ans;ans=Zero;
	for(;b;b>>=1,a*=a)
		if(b&1)
			ans*=a;
	return ans;
}
#define lson (u<<1)
#define rson (u<<1|1)
inline void pushup(int u)
{
	val[u]=val[lson]+val[rson];
	return;
}
inline void pushdown(int u,int l,int r)
{
	if(lazy[u]!=Zero)
	{
		lazy[lson]*=lazy[u];
		lazy[rson]*=lazy[u];
		val[lson]*=lazy[u];
		val[rson]*=lazy[u];
		lazy[u]=Zero;
	}
	return;
}
inline void buildtr(int u,int l,int r)
{
	if(l==r)
	{
		val[u]=fib(base,a[l]-1);
		return;
	}
	lazy[u]=Zero;
	reg int mid=(l+r)>>1;
	buildtr(lson,l,mid);
	buildtr(rson,mid+1,r);
	pushup(u);
	return;
}
inline void modify(int u,int l,int r,int ql,int qr,Mat k)
{
	if(ql<=l&&r<=qr)
	{
		lazy[u]*=k;
		val[u]*=k;
		return;
	}
	pushdown(u,l,r);
	reg int mid=(l+r)>>1;
	if(ql<=mid)
		modify(lson,l,mid,ql,qr,k);
	if(mid<qr)
		modify(rson,mid+1,r,ql,qr,k);
	pushup(u);
	return;
}
inline Mat query(int u,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr)
		return val[u];
	pushdown(u,l,r);
	reg int mid=(l+r)>>1;
	reg Mat ans;ans.clear();
	if(ql<=mid)
		ans+=query(lson,l,mid,ql,qr);
	if(mid<qr)
		ans+=query(rson,mid+1,r,ql,qr);
	return ans;
}
template <class t> inline void read(t &s)
{
	s=0;
	reg int f=1;
	reg char c=getchar();
	while(!isdigit(c))
	{
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while(isdigit(c))
		s=(s<<3)+(s<<1)+(c^48),c=getchar();
	s*=f;
	return;
}
signed main(void)
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;++i)
		read(a[i]);
	buildtr(1,1,n);
	reg int opt,l,r,x;
	for(int i=1;i<=m;++i)
	{
		read(opt);read(l);read(r);
		if(opt==1)
		{
			read(x);
			modify(1,1,n,l,r,fib(base,x));
		}
		else
			printf("%lld\n",(query(1,1,n,l,r)*One).a[0][0]);
	}
	return 0;
}
上一篇:本地MD搬运


下一篇:vue的富文本编辑器使用