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;
}
posted @ 2021-11-17 00:05  I_N_V  阅读(29)  评论(0编辑  收藏  举报