Sasha and Array
题目描述
题解
首先斐波那契数f(n)
\[\begin{pmatrix}
f(n)\\
f(n-1)\\
\end{pmatrix}=
\begin{pmatrix}
1&1\\
1&0\\
\end{pmatrix}*
\begin{pmatrix}
f(n-1)\\
f(n-2)\\
\end{pmatrix}=
\begin{pmatrix}
1&1\\
1&0\\
\end{pmatrix}^n*
\begin{pmatrix}
0\\
1\\
\end{pmatrix}=
A^n*\begin{pmatrix}0\\1\\\end{pmatrix}
\]
对于这道题来说,区间加以及求和是没法简单映射到\(f(a_i)\)的
那么我们可以考虑用线段树维护递推式。
线段树的节点存储为矩阵
根据矩阵具有结合律和分配律的性质,我们可以在区间上传的时候将线段树上左右两个矩阵相加,然后乘以修改的A的x次幂,也就类似正常的线段树操作,只是节点挂的是矩阵
这道题细节还很多
1.矩阵相乘的时候注意顺序,因为矩阵没有交换律的性质
2.lz存的是矩阵,因为如果lz存的是幂次,那么每次传递的时候都要进行快速幂操作,会超时
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long
using namespace std;
const int maxn=5e5+101;
const int MOD=1e9+7;
const int inf=2147483647;
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,m,a[maxn];
struct Matrix{
ll a[2][2];
void init(){
a[0][0]=a[1][1]=1;
a[0][1]=a[1][0]=0;
}
void zero(){memset(a,0,sizeof(a));}
Matrix operator*(const Matrix& m2)const{
Matrix m;m.zero();
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
(m.a[i][j]+=a[i][k]*m2.a[k][j]%MOD)%=MOD;
}
}
}
return m;
}
Matrix operator+(const Matrix& m2)const{
Matrix m;m.zero();
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
(m.a[i][j]+=(a[i][j]+m2.a[i][j])%MOD)%=MOD;
}
}
return m;
}
Matrix operator^(ll y)const{
Matrix sum,x;sum.init();
memcpy(x.a,a,sizeof(a));
while(y){
if(y&1)sum=sum*x;
y>>=1;x=x*x;
}
return sum;
}
}T1,T2;
struct tree{
bool flag;
Matrix M,lz;
void init(){
M.zero();lz.init();flag=0;
}
}tr[maxn];
void add(int k,Matrix v){
tr[k].M=v*tr[k].M; //顺序!!!
tr[k].lz=tr[k].lz*v;
return;
}
void pushdown(int k){
if(tr[k].flag){
tr[k].flag=0;
tr[k<<1].flag=1;add(k<<1,tr[k].lz);
tr[k<<1|1].flag=1;add(k<<1|1,tr[k].lz);
tr[k].lz.init();
}
return ;
}
void build(int k,int l,int r){
tr[k].init();
if(l==r){
tr[k].M=(T1^a[l])*T2;
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tr[k].M=tr[k<<1].M+tr[k<<1|1].M;
return ;
}
ll query(int k,int l,int r,int L,int R){
if(r<L || l>R)return 0;
if(L<=l && r<=R)return tr[k].M.a[0][0];
int mid=(l+r)>>1;pushdown(k);
return (query(k<<1,l,mid,L,R)+query(k<<1|1,mid+1,r,L,R))%MOD;
}
void update(int k,int l,int r,int L,int R,Matrix v){
if(r<L || l>R)return ;
if(L<=l && r<=R){
tr[k].flag=1;add(k,v);
return ;
}
int mid=(l+r)>>1;pushdown(k);
update(k<<1,l,mid,L,R,v);update(k<<1|1,mid+1,r,L,R,v);
tr[k].M=tr[k<<1].M+tr[k<<1|1].M;
return ;
}
int main(){
n=read();m=read();
T1.a[0][0]=T1.a[0][1]=T1.a[1][0]=1;T1.a[1][1]=0;
T2.a[0][0]=0;T2.a[1][0]=1;
for(int i=1;i<=n;i++)a[i]=read();build(1,1,n);
for(int i=1;i<=m;i++){
int opt,l,r,x;
opt=read();l=read();r=read();
if(opt==1){
x=read();Matrix ss=T1^x; //先处理,省时间
update(1,1,n,l,r,ss);
}
else printf("%lld\n",(query(1,1,n,l,r)%MOD+MOD)%MOD);
}
return 0;
}