题目:点击打开链接
题意:给出有n个元素的数列ai(1<=i<=n)以及m次操作,操作分为两种:①将区间[l,r]的数加x;②询问∑f(ai)(l<=i<=r),其中f(x)是斐波那契数列的第x个数
分析:容易想到用快速矩阵幂求斐波那契数列,同时用线段树储存和矩阵以及lazy矩阵,如果lazy标记为指数的话每次更新都要用一遍快速矩阵幂,就会超时。因为矩阵乘法满足分配律,且区间[l,r]加上x可以表示为乘上x次q矩阵,所以线段树维护矩阵之和,同时每次更新的时候,x可以先用快速矩阵幂,求出变换x次后的矩阵,然后在线段树中更新,即和矩阵和lazy矩阵乘上该矩阵,表示加上区间的数加上x后的斐波那契数之和了。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = 3e18;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=100010;
const int Matsize=2;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
struct Mat
{
ll mat[Matsize][Matsize];
void init()
{
for(int i=0;i<Matsize;i++)
{
for(int j=0;j<Matsize;j++) mat[i][j]=0;
mat[i][i]=1;
}
}
Mat operator*(const Mat &t)const
{
Mat ans;
memset(ans.mat,0,sizeof(ans.mat));
for(int k=0;k<Matsize;k++)
for(int i=0;i<Matsize;i++)
for(int j=0;j<Matsize;j++)
ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*t.mat[k][j])%MOD;
return ans;
}
Mat operator+(const Mat &t)const
{
Mat ans;
for(int i=0;i<Matsize;i++)
for(int j=0;j<Matsize;j++)
ans.mat[i][j]=(mat[i][j]+t.mat[i][j])%MOD;
return ans;
}
};
int n,m,op,l,r;
Mat a[N<<2],lazy[N<<2],mt;
ll x;
Mat pow_M(ll m)
{
Mat res;
res.init();
mt.mat[0][0]=mt.mat[0][1]=mt.mat[1][0]=1,mt.mat[1][1]=0;
while(m)
{
if(m&1) res=res*mt;
mt=mt*mt;
m>>=1;
}
return res;
}
void pushup(int rt)
{
a[rt]=a[rt<<1]+a[rt<<1|1];
}
void pushdown(int rt)
{
lazy[rt<<1]=lazy[rt<<1]*lazy[rt];
lazy[rt<<1|1]=lazy[rt<<1|1]*lazy[rt];
a[rt<<1]=a[rt<<1]*lazy[rt];
a[rt<<1|1]=a[rt<<1|1]*lazy[rt];
lazy[rt].init();
}
void build(int l,int r,int rt)
{
a[rt].init();
lazy[rt].init();
if(l==r)
{
ll t;
scanf("%I64d",&t);
a[rt]=pow_M(t-1);
return;
}
int m=l+r>>1;
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,Mat x,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
a[rt]=a[rt]*x;
lazy[rt]=lazy[rt]*x;
return;
}
pushdown(rt);
int m=l+r>>1;
if(L<=m) update(L,R,x,lson);
if(m<R) update(L,R,x,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) return a[rt].mat[0][0];
pushdown(rt);
int m=l+r>>1;
ll res=0;
if(L<=m) res=(res+query(L,R,lson))%MOD;
if(m<R) res=(res+query(L,R,rson))%MOD;
return res;
}
int main()
{
scanf("%d%d",&n,&m);
build(1,n,1);
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%I64d",&l,&r,&x);
Mat t=pow_M(x);
update(l,r,t,1,n,1);
}
else
{
scanf("%d%d",&l,&r);
printf("%I64d\n",query(l,r,1,n,1));
}
}
}